added yield

This commit is contained in:
Sven Vogel 2022-10-27 21:34:22 +02:00
parent 6e5461ce33
commit b42f49c340
4 changed files with 84 additions and 26 deletions

View File

@ -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.
Its a functional language, having no concept of classes or inheritance. Types are static and must be known at compile time.
It contains features such as:
1. a COMEFROM keyword (inverse goto) 1. a COMEFROM keyword (inverse goto)
2. a ```don't``` code block which never executes 2. a `don't` code block which never executes
3. ```rand(x)``` returns x, always. 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 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 &gt; 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>&nbsp;</td></tr><tr><td>break</td><td>Exits a loop immediately</td><td>&nbsp;</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>&nbsp;</td></tr></tbody></table>
### Example code
```plaintext
foo(bar: int, abc:int) = int {
bar + abc
}
main {
foo(4, 5)
}
```

View File

@ -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)
} }
} }
"; ";

View File

@ -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

View File

@ -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);