non-constant range expressions
This commit is contained in:
parent
3037c65f68
commit
38de69dc93
6 changed files with 87 additions and 24 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
println("Fibonacci sequence:")
|
println("Fibonacci sequence:")
|
||||||
let fib = [1,1]
|
let fib = [1,1]
|
||||||
|
|
||||||
for i in 2..10:
|
let r=10
|
||||||
|
|
||||||
|
for i in 2..r:
|
||||||
fib.push(fib[i-2] + fib[i-1])
|
fib.push(fib[i-2] + fib[i-1])
|
||||||
println(fib)
|
println(fib)
|
||||||
|
|
@ -212,7 +212,7 @@ impl AsmPass {
|
||||||
self.emit(Goto(0));
|
self.emit(Goto(0));
|
||||||
let goto_addr2 = self.chunk.code.len() - 1; // placeholder
|
let goto_addr2 = self.chunk.code.len() - 1; // placeholder
|
||||||
self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len());
|
self.chunk.code[goto_addr1] = GotoIfNot(self.chunk.code.len());
|
||||||
self.chunk.code[goto_addr2] = Op::Goto(self.chunk.code.len());
|
self.chunk.code[goto_addr2] = Goto(self.chunk.code.len());
|
||||||
}
|
}
|
||||||
IfElseExpression {
|
IfElseExpression {
|
||||||
condition,
|
condition,
|
||||||
|
|
@ -435,8 +435,8 @@ impl AsmPass {
|
||||||
Expression::FieldGet { .. } => {}
|
Expression::FieldGet { .. } => {}
|
||||||
Expression::Range { lower, upper, .. } => {
|
Expression::Range { lower, upper, .. } => {
|
||||||
// opposite order, because we have to assign last one first to the loop variable
|
// opposite order, because we have to assign last one first to the loop variable
|
||||||
self.compile_expression(namespace, upper, symbols, registry)?;
|
// self.compile_expression(namespace, upper, symbols, registry)?;
|
||||||
self.compile_expression(namespace, lower, symbols, registry)?;
|
// self.compile_expression(namespace, lower, symbols, registry)?;
|
||||||
}
|
}
|
||||||
Expression::ForStatement {
|
Expression::ForStatement {
|
||||||
loop_var,
|
loop_var,
|
||||||
|
|
@ -446,17 +446,24 @@ impl AsmPass {
|
||||||
// 1. step var index
|
// 1. step var index
|
||||||
let step_const_index = self.emit_constant(Value::I64(1));
|
let step_const_index = self.emit_constant(Value::I64(1));
|
||||||
// 2. range expression
|
// 2. range expression
|
||||||
self.compile_expression(namespace, range, symbols, registry)?;
|
// self.compile_expression(namespace, range, symbols, registry)?;
|
||||||
//save the constants for lower and upper bounds of the range
|
// //save the constants for lower and upper bounds of the range
|
||||||
let start_index = self.chunk.constants.len() - 1;
|
// let start_index = self.chunk.constants.len() - 1;
|
||||||
let end_index = self.chunk.constants.len() - 2;
|
// let end_index = self.chunk.constants.len() - 2;
|
||||||
|
|
||||||
let name = loop_var.lexeme.as_str();
|
let name = loop_var.lexeme.as_str();
|
||||||
let loop_var_name_index = self.chunk.add_var(&loop_var.token_type, name);
|
let loop_var_name_index = self.chunk.add_var(&loop_var.token_type, name);
|
||||||
self.vars.insert(name.to_string(), loop_var_name_index);
|
self.vars.insert(name.to_string(), loop_var_name_index);
|
||||||
|
|
||||||
// 3. start index
|
// 3. start index
|
||||||
self.emit(Constant(start_index));
|
let end=
|
||||||
|
if let Expression::Range { lower, upper, .. } = range.deref() {
|
||||||
|
self.compile_expression(namespace, lower, symbols, registry)?;
|
||||||
|
upper.clone()
|
||||||
|
} else {
|
||||||
|
unreachable!("range expression should be a range expression")
|
||||||
|
};
|
||||||
|
|
||||||
self.emit(Assign(loop_var_name_index));
|
self.emit(Assign(loop_var_name_index));
|
||||||
|
|
||||||
let return_addr = self.chunk.code.len();
|
let return_addr = self.chunk.code.len();
|
||||||
|
|
@ -465,7 +472,7 @@ impl AsmPass {
|
||||||
self.emit(Constant(step_const_index));
|
self.emit(Constant(step_const_index));
|
||||||
self.emit(Add);
|
self.emit(Add);
|
||||||
self.emit(Assign(loop_var_name_index));
|
self.emit(Assign(loop_var_name_index));
|
||||||
self.emit(Constant(end_index));
|
self.compile_expression(namespace, &end, symbols, registry)?;
|
||||||
self.emit(Get(loop_var_name_index));
|
self.emit(Get(loop_var_name_index));
|
||||||
self.emit(GreaterEqual);
|
self.emit(GreaterEqual);
|
||||||
self.emit(GotoIf(return_addr));
|
self.emit(GotoIf(return_addr));
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ use crate::compiler::tokens::TokenType::{
|
||||||
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For,
|
Bang, Bool, Char, Colon, DateTime, Dot, Else, Eof, Eol, Equal, False, FloatingPoint, Fn, For,
|
||||||
Greater, GreaterEqual, GreaterGreater, Identifier, If, In, Indent, Integer, LeftBrace,
|
Greater, GreaterEqual, GreaterGreater, Identifier, If, In, Indent, Integer, LeftBrace,
|
||||||
LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus,
|
LeftBracket, LeftParen, Less, LessEqual, LessLess, Let, ListType, MapType, Minus, Object, Plus,
|
||||||
Range, RightBrace, RightBracket, RightParen, SingleRightArrow, Slash, Star, StringType,
|
Range, RightBrace, RightBracket, RightParen, SingleRightArrow, Slash, Star, StringType, True,
|
||||||
True, U32, U64, Unknown,
|
U32, U64, Unknown,
|
||||||
};
|
};
|
||||||
use crate::compiler::tokens::{Token, TokenType};
|
use crate::compiler::tokens::{Token, TokenType};
|
||||||
use crate::errors::CompilerError::{
|
use crate::errors::CompilerError::{
|
||||||
|
|
@ -686,7 +686,8 @@ impl AstCompiler {
|
||||||
debug!("{:?}", token);
|
debug!("{:?}", token);
|
||||||
if self.match_token(&[LeftParen]) {
|
if self.match_token(&[LeftParen]) {
|
||||||
self.function_call(token.clone(), symbol_table)?
|
self.function_call(token.clone(), symbol_table)?
|
||||||
} else if self.match_token(&[Colon]) {
|
} else if self.peek().token_type == Colon && *self.peek_next() != Eol {
|
||||||
|
self.advance();
|
||||||
self.named_parameter(&token, symbol_table)?
|
self.named_parameter(&token, symbol_table)?
|
||||||
} else {
|
} else {
|
||||||
self.variable_lookup(&token, symbol_table)?
|
self.variable_lookup(&token, symbol_table)?
|
||||||
|
|
@ -823,6 +824,14 @@ impl AstCompiler {
|
||||||
&self.tokens[self.current]
|
&self.tokens[self.current]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peek_next(&self) -> &TokenType {
|
||||||
|
if self.current + 1 >= self.tokens.len() {
|
||||||
|
&Unknown
|
||||||
|
} else {
|
||||||
|
&self.tokens[self.current + 1].token_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn previous(&self) -> &Token {
|
fn previous(&self) -> &Token {
|
||||||
&self.tokens[self.current - 1]
|
&self.tokens[self.current - 1]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -406,6 +406,21 @@ sum
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn non_constant_range_loop() {
|
||||||
|
assert_eq!(
|
||||||
|
run(r#"
|
||||||
|
let sum=0
|
||||||
|
let s = 1
|
||||||
|
let f = 5
|
||||||
|
for a in s..f:
|
||||||
|
sum = sum + a
|
||||||
|
sum
|
||||||
|
"#),
|
||||||
|
Ok(Value::I64(15))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn global_function_call() {
|
fn global_function_call() {
|
||||||
let value = run(r#"now()"#);
|
let value = run(r#"now()"#);
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::errors::CompilerError::{IllegalCharLength, UnexpectedIdentifier, Unterminated};
|
use crate::compiler::tokens::TokenType::{BitXor, FloatingPoint, In, Integer, Question, U32, U64};
|
||||||
use crate::errors::{CompilerError, CompilerErrorAtLine};
|
|
||||||
use crate::compiler::tokens::TokenType::{BitXor, FloatingPoint, Integer, Question, U32, U64};
|
|
||||||
use crate::keywords;
|
|
||||||
use crate::compiler::tokens::{
|
use crate::compiler::tokens::{
|
||||||
Token,
|
Token,
|
||||||
TokenType::{self},
|
TokenType::{self},
|
||||||
};
|
};
|
||||||
|
use crate::errors::CompilerError::{IllegalCharLength, UnexpectedIdentifier, Unterminated};
|
||||||
|
use crate::errors::{CompilerError, CompilerErrorAtLine};
|
||||||
|
use crate::keywords;
|
||||||
|
use axum::http::header::ToStrError;
|
||||||
|
|
||||||
pub fn scan(source: &str) -> Result<Vec<Token>, CompilerErrorAtLine> {
|
pub fn scan(source: &str) -> Result<Vec<Token>, CompilerErrorAtLine> {
|
||||||
let scanner = Scanner {
|
let scanner = Scanner {
|
||||||
|
|
@ -47,7 +48,14 @@ impl Scanner {
|
||||||
'[' => self.add_token(TokenType::LeftBracket),
|
'[' => self.add_token(TokenType::LeftBracket),
|
||||||
']' => self.add_token(TokenType::RightBracket),
|
']' => self.add_token(TokenType::RightBracket),
|
||||||
',' => self.add_token(TokenType::Comma),
|
',' => self.add_token(TokenType::Comma),
|
||||||
'.' => self.add_token(TokenType::Dot),
|
'.' => {
|
||||||
|
let t = if self.match_next('.') {
|
||||||
|
TokenType::Range
|
||||||
|
} else {
|
||||||
|
TokenType::Dot
|
||||||
|
};
|
||||||
|
self.add_token(t);
|
||||||
|
}
|
||||||
'-' => {
|
'-' => {
|
||||||
let t = if self.match_next('>') {
|
let t = if self.match_next('>') {
|
||||||
TokenType::SingleRightArrow
|
TokenType::SingleRightArrow
|
||||||
|
|
@ -203,14 +211,31 @@ impl Scanner {
|
||||||
let lower: String = self.chars[self.start..self.current].iter().collect();
|
let lower: String = self.chars[self.start..self.current].iter().collect();
|
||||||
self.match_next('.');
|
self.match_next('.');
|
||||||
self.match_next('.');
|
self.match_next('.');
|
||||||
self.add_token_with_value(Integer, lower);
|
let tokentype = if lower.parse::<i64>().is_err() {
|
||||||
|
TokenType::Identifier
|
||||||
|
} else {
|
||||||
|
Integer
|
||||||
|
};
|
||||||
|
self.add_token_with_value(tokentype, lower);
|
||||||
self.add_token(TokenType::Range);
|
self.add_token(TokenType::Range);
|
||||||
self.start = self.current;
|
self.start = self.current;
|
||||||
|
let tokentype = if self.peek().is_ascii_digit() {
|
||||||
|
Integer
|
||||||
|
} else {
|
||||||
|
TokenType::Identifier
|
||||||
|
};
|
||||||
|
if self.peek().is_ascii_digit() {
|
||||||
while self.peek().is_ascii_digit() {
|
while self.peek().is_ascii_digit() {
|
||||||
self.advance();
|
self.advance();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.advance();
|
||||||
|
while self.peek().is_alphanumeric() {
|
||||||
|
self.advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
let upper: String = self.chars[self.start..self.current].iter().collect();
|
let upper: String = self.chars[self.start..self.current].iter().collect();
|
||||||
self.add_token_with_value(Integer, upper);
|
self.add_token_with_value(tokentype, upper);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn char(&mut self) -> Result<(), CompilerErrorAtLine> {
|
fn char(&mut self) -> Result<(), CompilerErrorAtLine> {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use crate::DATE_FORMAT_TIMEZONE;
|
||||||
use crate::errors::ValueError;
|
use crate::errors::ValueError;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
@ -5,7 +6,6 @@ use std::collections::HashMap;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
||||||
use crate::DATE_FORMAT_TIMEZONE;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
|
|
@ -190,7 +190,12 @@ impl Display for Value {
|
||||||
Value::DateTime(v) => write!(f, "{}", v.format(DATE_FORMAT_TIMEZONE)),
|
Value::DateTime(v) => write!(f, "{}", v.format(DATE_FORMAT_TIMEZONE)),
|
||||||
Value::Enum => write!(f, "enum"),
|
Value::Enum => write!(f, "enum"),
|
||||||
Value::ObjectType(o) => write!(f, "{}: {:?}", o.definition, o.fields),
|
Value::ObjectType(o) => write!(f, "{}: {:?}", o.definition, o.fields),
|
||||||
Value::List(v) => write!(f, "{:?}", v),
|
Value::List(v) => {
|
||||||
|
for i in &v[0..v.len() - 1] {
|
||||||
|
write!(f, "{}, ", i)?;
|
||||||
|
}
|
||||||
|
write!(f, "{}", v[v.len() - 1])
|
||||||
|
}
|
||||||
Value::Map(map) => to_string(f, map),
|
Value::Map(map) => to_string(f, map),
|
||||||
Value::Error(v) => write!(f, "{}", v),
|
Value::Error(v) => write!(f, "{}", v),
|
||||||
Value::Void => write!(f, "()"),
|
Value::Void => write!(f, "()"),
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue