Compare commits
3 commits
2574165cd1
...
79ee784a5b
Author | SHA1 | Date | |
---|---|---|---|
79ee784a5b | |||
2024677225 | |||
89e6eff198 |
7 changed files with 57 additions and 23 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -22,7 +22,7 @@ checksum = "b03f7fbd470aa8b3ad163c85cce8bccfc11cc9c44ef12da0a4eddd98bd307352"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spl"
|
name = "spl"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"multicall",
|
"multicall",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "spl"
|
name = "spl"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Stack Pogramming Language: A simple, concise scripting language."
|
description = "Stack Pogramming Language: A simple, concise scripting language."
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
12
README.md
12
README.md
|
@ -10,7 +10,7 @@ func main { mega | with args ;
|
||||||
{ str | " " concat } swap:map
|
{ str | " " concat } swap:map
|
||||||
&print swap:foreach
|
&print swap:foreach
|
||||||
"" println
|
"" println
|
||||||
println <{ "and with that, we're done" }
|
println<"and with that, we're done">
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -177,19 +177,19 @@ func main { mega | with args ;
|
||||||
```
|
```
|
||||||
- SPL actually isn't fully concatenative. It supports postfix arguments as well:
|
- SPL actually isn't fully concatenative. It supports postfix arguments as well:
|
||||||
```js
|
```js
|
||||||
println <{ "and with that, we're done" }
|
println<"and with that, we're done">
|
||||||
```
|
```
|
||||||
This is actually not a special interpreter feature, more so is it a special
|
This is actually not a special interpreter feature, more so is it a special
|
||||||
lexer feature. This is 100% equivalent with the non-postfix version, where the
|
lexer feature. This is 100% equivalent with the non-postfix version, where the
|
||||||
string is right before the `println`.
|
string is right before the `println`.
|
||||||
|
|
||||||
The same can be done for object calls. Let's rewrite the previous code with
|
The same can be done for object calls. Let's rewrite the previous code with
|
||||||
postfix:
|
prefix notation:
|
||||||
```js
|
```js
|
||||||
Range:new <{ 0 5 }
|
Range:new<0 5>
|
||||||
:iter
|
:iter
|
||||||
:map <{ { | 5 * } }
|
:map<{ | 5 * }>
|
||||||
:foreach <{ { | _str println } }
|
:foreach<{ | _str println }>
|
||||||
```
|
```
|
||||||
|
|
||||||
I lied. This is now no longer 100% equivalent. Let's look at what happens
|
I lied. This is now no longer 100% equivalent. Let's look at what happens
|
||||||
|
|
32
src/lexer.rs
32
src/lexer.rs
|
@ -24,6 +24,15 @@ pub fn lex(compat: bool, input: String) -> Result<Words, LexerError> {
|
||||||
fn read_block(
|
fn read_block(
|
||||||
str_words: &[String],
|
str_words: &[String],
|
||||||
isfn: bool,
|
isfn: bool,
|
||||||
|
compat: bool,
|
||||||
|
) -> Result<(Option<u32>, Words, usize), LexerError> {
|
||||||
|
read_block_dyn(str_words, isfn, "}".to_owned(), compat)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_block_dyn(
|
||||||
|
str_words: &[String],
|
||||||
|
isfn: bool,
|
||||||
|
endword: String,
|
||||||
mut compat: bool,
|
mut compat: bool,
|
||||||
) -> Result<(Option<u32>, Words, usize), LexerError> {
|
) -> Result<(Option<u32>, Words, usize), LexerError> {
|
||||||
if str_words.is_empty() {
|
if str_words.is_empty() {
|
||||||
|
@ -111,8 +120,8 @@ fn read_block(
|
||||||
x if x.len() >= 2 && &x[0..2] == "!{" => {
|
x if x.len() >= 2 && &x[0..2] == "!{" => {
|
||||||
words.push(Word::Const(Value::Str(x[2..].to_owned())));
|
words.push(Word::Const(Value::Str(x[2..].to_owned())));
|
||||||
}
|
}
|
||||||
"<{" => {
|
"<" => {
|
||||||
let block = read_block(&str_words[i + 1..], false, compat)?;
|
let block = read_block_dyn(&str_words[i + 1..], false, ">".to_owned(), compat)?;
|
||||||
i += block.2 + 1;
|
i += block.2 + 1;
|
||||||
let mut block = block.1.words;
|
let mut block = block.1.words;
|
||||||
match words.remove(words.len() - 1) {
|
match words.remove(words.len() - 1) {
|
||||||
|
@ -227,7 +236,7 @@ fn read_block(
|
||||||
}
|
}
|
||||||
words.push(Word::Key(Keyword::With(vars)));
|
words.push(Word::Key(Keyword::With(vars)));
|
||||||
}
|
}
|
||||||
"}" => {
|
x if x == endword => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
x if x.starts_with('\"') => {
|
x if x.starts_with('\"') => {
|
||||||
|
@ -286,7 +295,11 @@ fn read_block(
|
||||||
Ok((rem, Words { words }, i))
|
Ok((rem, Words { words }, i))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(input: String) -> Vec<String> {
|
pub fn parse(mut input: String) -> Vec<String> {
|
||||||
|
if input.starts_with("#!") {
|
||||||
|
input = input.split_off(input.find('\n').expect("cannot have #! without newline"));
|
||||||
|
}
|
||||||
|
|
||||||
let mut words = Vec::new();
|
let mut words = Vec::new();
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
|
|
||||||
|
@ -346,6 +359,17 @@ fn parse(input: String) -> Vec<String> {
|
||||||
if c == '(' || c == ')' {
|
if c == '(' || c == ')' {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if c == '<' || c == '>' {
|
||||||
|
if s.is_empty() {
|
||||||
|
words.push(c.to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
words.push(s);
|
||||||
|
s = String::new();
|
||||||
|
was_in_string = false;
|
||||||
|
words.push(c.to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if c == ' ' || c == '\t' {
|
if c == ' ' || c == '\t' {
|
||||||
if s.is_empty() {
|
if s.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -1,4 +1,6 @@
|
||||||
use spl::{lex, oxidizer::RustAppBuilder, start_file_in_runtime, Runtime, SetRuntime};
|
use spl::{
|
||||||
|
lex, oxidizer::RustAppBuilder, sasm::sasm_write, start_file_in_runtime, Runtime, SetRuntime,
|
||||||
|
};
|
||||||
|
|
||||||
use std::{env::args, fs};
|
use std::{env::args, fs};
|
||||||
|
|
||||||
|
@ -6,9 +8,14 @@ fn main() {
|
||||||
Runtime::new().set();
|
Runtime::new().set();
|
||||||
let mut args = args().skip(1);
|
let mut args = args().skip(1);
|
||||||
let arg = &args.next().unwrap_or("#repl.spl".to_owned());
|
let arg = &args.next().unwrap_or("#repl.spl".to_owned());
|
||||||
if arg == "--build" || arg == "--run" || arg == "--buildrun" {
|
if arg == "--build" || arg == "--run" || arg == "--buildrun" || arg == "--debug" {
|
||||||
let file = args.next().unwrap();
|
let file = args.next().unwrap();
|
||||||
let data = fs::read_to_string(file.clone()).expect("unable to read specified file");
|
let data = fs::read_to_string(file.clone()).expect("unable to read specified file");
|
||||||
|
if arg == "--debug" {
|
||||||
|
println!("words: {}", spl::parse(data.clone()).join(" "));
|
||||||
|
println!("{}", sasm_write(lex(false, data).unwrap()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
let build_only = arg == "--build";
|
let build_only = arg == "--build";
|
||||||
if build_only {
|
if build_only {
|
||||||
println!("Building SPL with specified natives file...");
|
println!("Building SPL with specified natives file...");
|
||||||
|
|
7
std.spl
7
std.spl
|
@ -82,6 +82,9 @@ construct _str_ext {
|
||||||
starts-with { bool | with beginning this ;
|
starts-with { bool | with beginning this ;
|
||||||
beginning:to-bytes this:to-bytes:starts-with
|
beginning:to-bytes this:to-bytes:starts-with
|
||||||
}
|
}
|
||||||
|
_char { int | with this ;
|
||||||
|
0 (this _array):get
|
||||||
|
}
|
||||||
} include _str_ext in str
|
} include _str_ext in str
|
||||||
|
|
||||||
construct _mega-ext {
|
construct _mega-ext {
|
||||||
|
@ -398,9 +401,9 @@ func concat { str | with a b ;
|
||||||
|
|
||||||
func nconcat { str | with amt ;
|
func nconcat { str | with amt ;
|
||||||
_array
|
_array
|
||||||
(amt 1 -):foreach <{ { | pop
|
(amt 1 -):foreach<{ | pop
|
||||||
swap _array swap aadd
|
swap _array swap aadd
|
||||||
} }
|
}>
|
||||||
_str
|
_str
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
test.spl
12
test.spl
|
@ -142,10 +142,10 @@ func main { int | with args ;
|
||||||
|
|
||||||
"testing messages" println
|
"testing messages" println
|
||||||
def bus messaging:Bus:new =bus
|
def bus messaging:Bus:new =bus
|
||||||
bus:subscribe <{ "testmsg1" { | with message ; message:name print " called1 1" println } }
|
bus:subscribe<"testmsg1" { | with message ; message:name print " called1 1" println }>
|
||||||
bus:subscribe <{ "testmsg1" { | with message ; message:name print " called1 2" println } }
|
bus:subscribe<"testmsg1" { | with message ; message:name print " called1 2" println }>
|
||||||
bus:subscribe <{ "testmsg2" { | with message ; message:name print " called2 1" println } }
|
bus:subscribe<"testmsg2" { | with message ; message:name print " called2 1" println }>
|
||||||
bus:subscribe <{ "testmsg2" { | with message ; message:name print " called2 2" println } }
|
bus:subscribe<"testmsg2" { | with message ; message:name print " called2 2" println }>
|
||||||
"testmsg1" bus:publish
|
"testmsg1" bus:publish
|
||||||
"testmsg2" bus:publish
|
"testmsg2" bus:publish
|
||||||
"testmsg1" bus:publish
|
"testmsg1" bus:publish
|
||||||
|
@ -154,7 +154,7 @@ func main { int | with args ;
|
||||||
100
|
100
|
||||||
}
|
}
|
||||||
|
|
||||||
func cached-test { mega | 1 "cached-test" cache <{ { mega | with i ;
|
func cached-test { mega | 1 "cached-test" cache<{ mega | with i ;
|
||||||
i 2 *
|
i 2 *
|
||||||
"calculated " i _str concat println
|
"calculated " i _str concat println
|
||||||
} } }
|
}>}
|
||||||
|
|
Loading…
Reference in a new issue