added yield
This commit is contained in:
parent
6e5461ce33
commit
b42f49c340
41
README.md
41
README.md
|
@ -1,7 +1,34 @@
|
|||
# Yard
|
||||
Yard is an funny programming language compiler and interpreter written in pure Rust
|
||||
It *will* contain features such as:
|
||||
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 get executed if the is false and doesn't if it is true
|
||||
## Yard
|
||||
|
||||
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)
|
||||
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 =
|
||||
r"
|
||||
#pi = 3.1415926535
|
||||
# this is pi
|
||||
pi = rat 3.1415926535
|
||||
|
||||
foo(x :int, y: rat) = bool {
|
||||
|
||||
yield maybe
|
||||
}
|
||||
|
||||
comment
|
||||
main {
|
||||
-- comment --
|
||||
unless 3 > 4 {
|
||||
a = 4 + 5;
|
||||
b = 0.3 + 7;
|
||||
a = 4 - 5; // also comment
|
||||
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) => {
|
||||
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);
|
||||
continue;
|
||||
} 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
|
||||
match &top {
|
||||
Token::LineBreak(_) => (), // valid whitespace
|
||||
Token::LineBreak(_) | Token::Terminator(_) => (), // valid whitespace
|
||||
_ => {
|
||||
top.print(MessageType::Error, "unresolvable token", source);
|
||||
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() {
|
||||
|
||||
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(|| {
|
||||
dbginf.print(MessageType::Error, "curly brace missmatch", source);
|
||||
panic!()
|
||||
|
@ -369,8 +374,9 @@ fn call_func(name: &str, declrs: &Vec<Declr>, _: &mut Scope, operands: &mut Vec<
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: push result type
|
||||
// operands.push();
|
||||
if let Some(typ) = declr.result_typ {
|
||||
operands.push(typ);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
for (x, f) in funcs.iter().enumerate() {
|
||||
println!("{:?}{:?}", declrs[x], f);
|
||||
println!("{:#?}{:#?}", declrs[x], f);
|
||||
}
|
||||
|
||||
funcs
|
||||
|
|
|
@ -186,6 +186,8 @@ pub enum Keyword {
|
|||
Loop,
|
||||
Break,
|
||||
Continue,
|
||||
Return,
|
||||
Yield
|
||||
}
|
||||
|
||||
impl Keyword {
|
||||
|
@ -195,7 +197,9 @@ impl Keyword {
|
|||
"while" => Keyword::While,
|
||||
"loop" => Keyword::Loop,
|
||||
"break" => Keyword::Break,
|
||||
"continue" => Keyword::Continue,
|
||||
"cont" => Keyword::Continue,
|
||||
"ret" => Keyword::Return,
|
||||
"yield" => Keyword::Yield,
|
||||
_ => panic!("Text not a known keyword {text}")
|
||||
}
|
||||
}
|
||||
|
@ -267,9 +271,9 @@ impl Prim {
|
|||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
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,
|
||||
/// index in source string where the token ends
|
||||
/// index in source string where the token ends in the current line
|
||||
end: usize,
|
||||
/// line number where the line in which the token is begins
|
||||
line: usize
|
||||
|
@ -303,10 +307,19 @@ impl DebugInfo {
|
|||
/// Error (message) in line 7: token `code`
|
||||
/// somewhere in here:
|
||||
/// --> `code line`
|
||||
/// ^^^^
|
||||
/// ```
|
||||
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!(" 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),
|
||||
/// Keywords like ```if```,```break```,```while```
|
||||
Keyword(Keyword, DebugInfo),
|
||||
Type(Prim, DebugInfo)
|
||||
Type(Prim, DebugInfo),
|
||||
/// Semicolon
|
||||
Terminator(DebugInfo)
|
||||
}
|
||||
|
||||
impl<'a> Token<'a> {
|
||||
|
@ -353,11 +368,12 @@ impl<'a> Token<'a> {
|
|||
Token::Decl(_, _, dbginf) => dbginf.print(error, arg, source),
|
||||
Token::Bool(_, 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! {
|
||||
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 line_count = 0;
|
||||
let mut line_start = 0;
|
||||
|
||||
for cap in TOKEN_REGEX.captures_iter(source) {
|
||||
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 let Some(mat) = group {
|
||||
let debug_info = DebugInfo {
|
||||
start: mat.start(),
|
||||
end: mat.end(),
|
||||
start: mat.start() - line_start,
|
||||
end: mat.end() - line_start,
|
||||
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),
|
||||
13 => {
|
||||
line_count += 1;
|
||||
line_start = mat.start();
|
||||
Token::LineBreak(debug_info)
|
||||
},
|
||||
14 => Token::Terminator(debug_info),
|
||||
|
||||
_ => {
|
||||
debug_info.print(MessageType::Error, "Unable to identify sequence as token", source);
|
||||
|
|
Loading…
Reference in New Issue