added yield
This commit is contained in:
parent
6e5461ce33
commit
b42f49c340
41
README.md
41
README.md
|
@ -1,7 +1,34 @@
|
||||||
# Yard
|
## Yard
|
||||||
Yard is an funny programming language compiler and interpreter written in pure Rust
|
|
||||||
It *will* contain features such as:
|
Yard is an funny programming language compiler and interpreter written in pure Rust.
|
||||||
1. a COMEFROM keyword (inverse goto)
|
Its a functional language, having no concept of classes or inheritance. Types are static and must be known at compile time.
|
||||||
2. a ```don't``` code block which never executes
|
It contains features such as:
|
||||||
3. ```rand(x)``` returns x, always.
|
|
||||||
4. no if. only `unless`, an inverted version of if. Meaning a block get executed if the is false and doesn't if it is true
|
1. a COMEFROM keyword (inverse goto)
|
||||||
|
2. a `don't` code block which never executes
|
||||||
|
3. `rand(x)` returns x, always.
|
||||||
|
4. no if. only `unless`, an inverted version of if. Meaning a block gets executed if the expression is false
|
||||||
|
5. three spaces start a single line comment
|
||||||
|
6. many ways of making comments: `// comment`, `:REM: comment`, `# comment`, `-- comment --` cuz we can
|
||||||
|
|
||||||
|
### Keywords
|
||||||
|
|
||||||
|
<table><tbody><tr><td>Syntax</td><td>Description</td><td>Example</td></tr><tr><td>Unless</td><td>Inverted if. Only executes the following block if the expression is false</td><td><pre><code class="language-plaintext">unless 3 > 4 {
|
||||||
|
// code block
|
||||||
|
}</code></pre></td></tr><tr><td>Loop</td><td>While(true)-Loop. Loops forever until either yield, ret, break are used.<br>Loop take no boolean expression.</td><td><pre><code class="language-plaintext">loop {
|
||||||
|
// code block
|
||||||
|
}</code></pre></td></tr><tr><td>cont</td><td>Short form for “continue”. Jumps to the next iteration of a loop</td><td> </td></tr><tr><td>break</td><td>Exits a loop immediately</td><td> </td></tr><tr><td>yield</td><td>Returns from a function with an argument as return value</td><td><pre><code class="language-plaintext">foo() = int {
|
||||||
|
yield 4
|
||||||
|
}</code></pre></td></tr><tr><td>ret</td><td>Short form for “return”. This keyword takes no argument and returns from a function. NOTE: if ret is used in a function with a return type, an error occurs.</td><td> </td></tr></tbody></table>
|
||||||
|
|
||||||
|
### Example code
|
||||||
|
|
||||||
|
```plaintext
|
||||||
|
foo(bar: int, abc:int) = int {
|
||||||
|
bar + abc
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
foo(4, 5)
|
||||||
|
}
|
||||||
|
```
|
18
src/main.rs
18
src/main.rs
|
@ -18,18 +18,24 @@ fn main() {
|
||||||
|
|
||||||
let source =
|
let source =
|
||||||
r"
|
r"
|
||||||
#pi = 3.1415926535
|
# this is pi
|
||||||
|
pi = rat 3.1415926535
|
||||||
|
|
||||||
foo(x :int, y: rat) = bool {
|
foo(x :int, y: rat) = bool {
|
||||||
|
yield maybe
|
||||||
}
|
}
|
||||||
|
comment
|
||||||
main {
|
main {
|
||||||
|
-- comment --
|
||||||
unless 3 > 4 {
|
unless 3 > 4 {
|
||||||
a = 4 + 5;
|
a = 4 - 5; // also comment
|
||||||
b = 0.3 + 7;
|
b:rat = 0.3 + 7
|
||||||
|
|
||||||
|
t = foo(a, b) :REM: comment 3
|
||||||
|
}
|
||||||
|
|
||||||
|
don't {
|
||||||
|
|
||||||
foo(a, b)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
|
@ -76,6 +76,11 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
|
|
||||||
Token::Type(typ, dbginf) => {
|
Token::Type(typ, dbginf) => {
|
||||||
if declr.results {
|
if declr.results {
|
||||||
|
if declr.result_typ.is_some() {
|
||||||
|
dbginf.print(MessageType::Error, "Function must return either nothing or a single type", source);
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
declr.result_typ = Some(*typ);
|
declr.result_typ = Some(*typ);
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
|
@ -202,7 +207,7 @@ fn discover_functions<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &str)
|
||||||
|
|
||||||
// if we have anything left it might be an error
|
// if we have anything left it might be an error
|
||||||
match &top {
|
match &top {
|
||||||
Token::LineBreak(_) => (), // valid whitespace
|
Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace
|
||||||
_ => {
|
_ => {
|
||||||
top.print(MessageType::Error, "unresolvable token", source);
|
top.print(MessageType::Error, "unresolvable token", source);
|
||||||
panic!()
|
panic!()
|
||||||
|
@ -233,7 +238,7 @@ fn discover_exprs<'a>(functions: &mut Vec<Func<'a>>, _: &Vec<Declr<'a>>, source:
|
||||||
while let Some(top) = func.raw.as_mut().unwrap().pop_front() {
|
while let Some(top) = func.raw.as_mut().unwrap().pop_front() {
|
||||||
|
|
||||||
match &top {
|
match &top {
|
||||||
Token::LineBreak(dbginf) => if !expr.is_empty() {
|
Token::LineBreak(dbginf) | Token::Terminator(dbginf) => if !expr.is_empty() {
|
||||||
blocks.last_mut().unwrap_or_else(|| {
|
blocks.last_mut().unwrap_or_else(|| {
|
||||||
dbginf.print(MessageType::Error, "curly brace missmatch", source);
|
dbginf.print(MessageType::Error, "curly brace missmatch", source);
|
||||||
panic!()
|
panic!()
|
||||||
|
@ -369,8 +374,9 @@ fn call_func(name: &str, declrs: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: push result type
|
if let Some(typ) = declr.result_typ {
|
||||||
// operands.push();
|
operands.push(typ);
|
||||||
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -537,7 +543,7 @@ pub fn parse<'a>(tokens: &mut VecDeque<crate::Token<'a>>, source: &'a str) -> Ve
|
||||||
parse_exprs(&mut funcs, &declrs, source);
|
parse_exprs(&mut funcs, &declrs, source);
|
||||||
|
|
||||||
for (x, f) in funcs.iter().enumerate() {
|
for (x, f) in funcs.iter().enumerate() {
|
||||||
println!("{:?}{:?}", declrs[x], f);
|
println!("{:#?}{:#?}", declrs[x], f);
|
||||||
}
|
}
|
||||||
|
|
||||||
funcs
|
funcs
|
||||||
|
|
|
@ -186,6 +186,8 @@ pub enum Keyword {
|
||||||
Loop,
|
Loop,
|
||||||
Break,
|
Break,
|
||||||
Continue,
|
Continue,
|
||||||
|
Return,
|
||||||
|
Yield
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keyword {
|
impl Keyword {
|
||||||
|
@ -195,7 +197,9 @@ impl Keyword {
|
||||||
"while" => Keyword::While,
|
"while" => Keyword::While,
|
||||||
"loop" => Keyword::Loop,
|
"loop" => Keyword::Loop,
|
||||||
"break" => Keyword::Break,
|
"break" => Keyword::Break,
|
||||||
"continue" => Keyword::Continue,
|
"cont" => Keyword::Continue,
|
||||||
|
"ret" => Keyword::Return,
|
||||||
|
"yield" => Keyword::Yield,
|
||||||
_ => panic!("Text not a known keyword {text}")
|
_ => panic!("Text not a known keyword {text}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,9 +271,9 @@ impl Prim {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
pub struct DebugInfo {
|
pub struct DebugInfo {
|
||||||
/// index in source string where the token begins
|
/// index in source string where the token begins in the current line
|
||||||
start: usize,
|
start: usize,
|
||||||
/// index in source string where the token ends
|
/// index in source string where the token ends in the current line
|
||||||
end: usize,
|
end: usize,
|
||||||
/// line number where the line in which the token is begins
|
/// line number where the line in which the token is begins
|
||||||
line: usize
|
line: usize
|
||||||
|
@ -303,10 +307,19 @@ impl DebugInfo {
|
||||||
/// Error (message) in line 7: token `code`
|
/// Error (message) in line 7: token `code`
|
||||||
/// somewhere in here:
|
/// somewhere in here:
|
||||||
/// --> `code line`
|
/// --> `code line`
|
||||||
|
/// ^^^^
|
||||||
/// ```
|
/// ```
|
||||||
pub fn print<'a>(&self, typ: MessageType, msg: &str, source: &'a str) {
|
pub fn print<'a>(&self, typ: MessageType, msg: &str, source: &'a str) {
|
||||||
println!("{} ({}) in line {}: token `{}`", typ.to_colored(), msg.bold().bright_white(), self.line, &source[self.start..self.end].bold());
|
println!("{} ({}) in line {}: token `{}`", typ.to_colored(), msg.bold().bright_white(), self.line, &source[self.start..self.end].bold());
|
||||||
println!(" somewhere in here:\n --> `{}`\n", source.lines().nth(self.line).unwrap().trim().bold().bright_white())
|
println!(" somewhere in here:\n --> `{}`", source.lines().nth(self.line).unwrap().trim().bold().bright_white());
|
||||||
|
|
||||||
|
for _ in 0..self.start + 6 {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
for _ in self.start..self.end {
|
||||||
|
print!("^");
|
||||||
|
}
|
||||||
|
println!("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +346,9 @@ pub enum Token<'a> {
|
||||||
Bool(bool, DebugInfo),
|
Bool(bool, DebugInfo),
|
||||||
/// Keywords like ```if```,```break```,```while```
|
/// Keywords like ```if```,```break```,```while```
|
||||||
Keyword(Keyword, DebugInfo),
|
Keyword(Keyword, DebugInfo),
|
||||||
Type(Prim, DebugInfo)
|
Type(Prim, DebugInfo),
|
||||||
|
/// Semicolon
|
||||||
|
Terminator(DebugInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Token<'a> {
|
impl<'a> Token<'a> {
|
||||||
|
@ -353,11 +368,12 @@ impl<'a> Token<'a> {
|
||||||
Token::Decl(_, _, dbginf) => dbginf.print(error, arg, source),
|
Token::Decl(_, _, dbginf) => dbginf.print(error, arg, source),
|
||||||
Token::Bool(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Bool(_, dbginf) => dbginf.print(error, arg, source),
|
||||||
Token::Keyword(_, dbginf) => dbginf.print(error, arg, source),
|
Token::Keyword(_, dbginf) => dbginf.print(error, arg, source),
|
||||||
|
Token::Terminator(dbginf) => dbginf.print(error, arg, source),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TOKEN_REGEX_SRC: &'static str = r"(#.*)|(unless|while|loop|break|continue)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n|;)";
|
const TOKEN_REGEX_SRC: &'static str = r"(#.*|--.*--|//.*|:REM:.*| .*)|(unless|while|loop|break|cont|ret|yield)|(int|rat|bool)|(true|false|ye|no|maybe)|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))?\s*=|([A-Za-z_]+)\s*(?::\s*([a-zA-Z0-9]+))|([A-Za-z_]+)|(\d*\.?\d+)|(!=|==|<=|<=|[&|+\-*/<>=])|([(){}])|(\n)|(;)";
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static::lazy_static! {
|
||||||
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
|
static ref TOKEN_REGEX: regex::Regex = regex::Regex::new(TOKEN_REGEX_SRC).unwrap();
|
||||||
|
@ -368,6 +384,7 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
|
||||||
let mut tokens = VecDeque::new();
|
let mut tokens = VecDeque::new();
|
||||||
|
|
||||||
let mut line_count = 0;
|
let mut line_count = 0;
|
||||||
|
let mut line_start = 0;
|
||||||
|
|
||||||
for cap in TOKEN_REGEX.captures_iter(source) {
|
for cap in TOKEN_REGEX.captures_iter(source) {
|
||||||
let mut enumerator = cap.iter().enumerate();
|
let mut enumerator = cap.iter().enumerate();
|
||||||
|
@ -388,8 +405,8 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
|
||||||
// if we have a match, save it as token
|
// if we have a match, save it as token
|
||||||
if let Some(mat) = group {
|
if let Some(mat) = group {
|
||||||
let debug_info = DebugInfo {
|
let debug_info = DebugInfo {
|
||||||
start: mat.start(),
|
start: mat.start() - line_start,
|
||||||
end: mat.end(),
|
end: mat.end() - line_start,
|
||||||
line: line_count
|
line: line_count
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -417,8 +434,10 @@ pub fn tokenize<'a>(source: &'a str) -> VecDeque<Token<'a>> {
|
||||||
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
|
12 => Token::Delemiter(mat.as_str().chars().nth(0).unwrap(), debug_info),
|
||||||
13 => {
|
13 => {
|
||||||
line_count += 1;
|
line_count += 1;
|
||||||
|
line_start = mat.start();
|
||||||
Token::LineBreak(debug_info)
|
Token::LineBreak(debug_info)
|
||||||
},
|
},
|
||||||
|
14 => Token::Terminator(debug_info),
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
debug_info.print(MessageType::Error, "Unable to identify sequence as token", source);
|
debug_info.print(MessageType::Error, "Unable to identify sequence as token", source);
|
||||||
|
|
Loading…
Reference in New Issue