non-constant range expressions

This commit is contained in:
Shautvast 2025-12-09 21:03:49 +01:00
parent 3037c65f68
commit 38de69dc93
6 changed files with 87 additions and 24 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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, "()"),