first step in type checking
This commit is contained in:
parent
1d58725559
commit
e2ddf94a00
7 changed files with 245 additions and 63 deletions
|
|
@ -3,7 +3,7 @@ use crate::value::Value;
|
||||||
use crate::vm::{
|
use crate::vm::{
|
||||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY,
|
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY,
|
||||||
OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE, OP_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL,
|
OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE, OP_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL,
|
||||||
OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP, OP_DEFINE, OP_GET
|
OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP, OP_DEFINE, OP_GET,OP_DEF_STRING
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
|
|
@ -74,9 +74,10 @@ impl Chunk {
|
||||||
OP_PRINT => self.simple_inst("PRT", offset),
|
OP_PRINT => self.simple_inst("PRT", offset),
|
||||||
OP_POP => self.simple_inst("POP", offset),
|
OP_POP => self.simple_inst("POP", offset),
|
||||||
OP_DEFINE => self.constant_inst("DEF", offset),
|
OP_DEFINE => self.constant_inst("DEF", offset),
|
||||||
|
OP_DEF_STRING => self.constant_inst("DEFSTR", offset),
|
||||||
OP_GET => self.constant_inst("GET", offset),
|
OP_GET => self.constant_inst("GET", offset),
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unknown instruction");
|
println!("Unknown instruction {}", instruction);
|
||||||
offset + 1
|
offset + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
169
src/compiler.rs
169
src/compiler.rs
|
|
@ -3,12 +3,15 @@ use crate::scanner::scan;
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vm::{
|
use crate::vm::{
|
||||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_FALSE,
|
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_CHAR, OP_DEF_DATE,
|
||||||
OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT,
|
OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_OBJ, OP_DEF_STRING, OP_DEFINE,
|
||||||
OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_TRUE,
|
OP_DIVIDE, OP_EQUAL, OP_FALSE, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL,
|
||||||
|
OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
|
||||||
|
OP_TRUE,
|
||||||
};
|
};
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::mem::discriminant;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
|
@ -23,6 +26,8 @@ pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
||||||
current_token: &tokens[0],
|
current_token: &tokens[0],
|
||||||
tokens: &tokens,
|
tokens: &tokens,
|
||||||
current: 0,
|
current: 0,
|
||||||
|
types: vec![],
|
||||||
|
locals: vec![],
|
||||||
previous: 0,
|
previous: 0,
|
||||||
had_error: false,
|
had_error: false,
|
||||||
};
|
};
|
||||||
|
|
@ -36,6 +41,8 @@ struct Compiler<'a> {
|
||||||
current: usize,
|
current: usize,
|
||||||
previous_token: &'a Token,
|
previous_token: &'a Token,
|
||||||
current_token: &'a Token,
|
current_token: &'a Token,
|
||||||
|
types: Vec<Token>,
|
||||||
|
locals: Vec<String>,
|
||||||
previous: usize,
|
previous: usize,
|
||||||
had_error: bool,
|
had_error: bool,
|
||||||
}
|
}
|
||||||
|
|
@ -63,10 +70,28 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
fn let_declaration(&mut self) -> anyhow::Result<()> {
|
fn let_declaration(&mut self) -> anyhow::Result<()> {
|
||||||
let index = self.parse_variable("Expect variable name")?;
|
let index = self.parse_variable("Expect variable name")?;
|
||||||
|
let mut var_type = None;
|
||||||
|
if self.check(TokenType::Colon) {
|
||||||
|
self.consume(TokenType::Colon, "must not happen")?;
|
||||||
|
match self.current_token.token_type {
|
||||||
|
TokenType::I32
|
||||||
|
| TokenType::I64
|
||||||
|
| TokenType::U32
|
||||||
|
| TokenType::U64
|
||||||
|
| TokenType::Date
|
||||||
|
| TokenType::String
|
||||||
|
| TokenType::Char
|
||||||
|
| TokenType::Bool
|
||||||
|
| TokenType::ListType
|
||||||
|
| TokenType::MapType => var_type = Some(self.current_token.token_type),
|
||||||
|
_ => return Err(anyhow!("Invalid type {:?}", self.current_token.token_type)),
|
||||||
|
}
|
||||||
|
self.advance()?;
|
||||||
|
}
|
||||||
if self.match_token(TokenType::Equal) {
|
if self.match_token(TokenType::Equal) {
|
||||||
self.expression()?;
|
self.expression(var_type)?;
|
||||||
self.consume(TokenType::Eol, "Expect end of line")?;
|
self.consume(TokenType::Eol, "Expect end of line")?;
|
||||||
self.define_variable(index)?;
|
self.define_variable(var_type, index)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"You cannot declare a variable without initializing it."
|
"You cannot declare a variable without initializing it."
|
||||||
|
|
@ -86,8 +111,23 @@ impl<'a> Compiler<'a> {
|
||||||
Ok(index)
|
Ok(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_variable(&mut self, index: usize) -> anyhow::Result<()> {
|
fn define_variable(&mut self, var_type: Option<TokenType>, index: usize) -> anyhow::Result<()> {
|
||||||
self.emit_bytes(OP_DEFINE, index as u16);
|
let def_op = match var_type {
|
||||||
|
Some(TokenType::I32) => OP_DEF_I32,
|
||||||
|
Some(TokenType::I64) => OP_DEF_I64,
|
||||||
|
Some(TokenType::U32) => OP_DEF_I64,
|
||||||
|
Some(TokenType::U64) => OP_DEF_I64,
|
||||||
|
Some(TokenType::Date) => OP_DEF_DATE,
|
||||||
|
Some(TokenType::String) => OP_DEF_STRING,
|
||||||
|
Some(TokenType::Char) => OP_DEF_CHAR,
|
||||||
|
Some(TokenType::Bool) => OP_DEF_BOOL,
|
||||||
|
Some(TokenType::ListType) => OP_DEF_LIST,
|
||||||
|
Some(TokenType::MapType) => OP_DEF_MAP,
|
||||||
|
Some(TokenType::Object) => OP_DEF_OBJ,
|
||||||
|
_ => OP_DEFINE,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.emit_bytes(def_op, index as u16);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,14 +141,17 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
fn expression_statement(&mut self) -> anyhow::Result<()> {
|
fn expression_statement(&mut self) -> anyhow::Result<()> {
|
||||||
debug!("expression statement");
|
debug!("expression statement");
|
||||||
self.expression()?;
|
self.expression(None)?;
|
||||||
self.emit_byte(OP_POP);
|
self.emit_byte(OP_POP);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_statement(&mut self) -> anyhow::Result<()> {
|
fn print_statement(&mut self) -> anyhow::Result<()> {
|
||||||
self.expression()?;
|
self.expression(None)?;
|
||||||
self.consume(TokenType::Eol, "No further expressions expected. Please continue on a new line after the first.\n")?;
|
self.consume(
|
||||||
|
TokenType::Eol,
|
||||||
|
"No further statements expected. Please start on a new line after the first one.\n",
|
||||||
|
)?;
|
||||||
self.emit_byte(OP_PRINT);
|
self.emit_byte(OP_PRINT);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -158,23 +201,27 @@ impl<'a> Compiler<'a> {
|
||||||
self.current_token.token_type == token_type
|
self.current_token.token_type == token_type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> anyhow::Result<()> {
|
fn expression(&mut self, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
self.parse_precedence(PREC_ASSIGNMENT)?;
|
self.parse_precedence(PREC_ASSIGNMENT, expected_type)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_precedence(&mut self, precedence: usize) -> anyhow::Result<()> {
|
fn parse_precedence(
|
||||||
|
&mut self,
|
||||||
|
precedence: usize,
|
||||||
|
expected_type: Option<TokenType>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
let rule = get_rule(&self.previous_token.token_type);
|
let rule = get_rule(&self.previous_token.token_type);
|
||||||
debug!("Precedence rule: {:?}", rule);
|
debug!("Precedence rule: {:?}", rule);
|
||||||
if let Some(prefix) = rule.prefix {
|
if let Some(prefix) = rule.prefix {
|
||||||
prefix(self)?;
|
prefix(self, expected_type)?;
|
||||||
while precedence <= get_rule(&self.current_token.token_type).precedence {
|
while precedence <= get_rule(&self.current_token.token_type).precedence {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
let infix_rule = get_rule(&self.previous_token.token_type).infix;
|
let infix_rule = get_rule(&self.previous_token.token_type).infix;
|
||||||
if let Some(infix) = infix_rule {
|
if let Some(infix) = infix_rule {
|
||||||
infix(self)?;
|
infix(self, expected_type)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -198,7 +245,7 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ParseFn = fn(&mut Compiler) -> anyhow::Result<()>;
|
type ParseFn = fn(&mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Rule {
|
struct Rule {
|
||||||
|
|
@ -217,38 +264,66 @@ impl Rule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number(s: &mut Compiler) -> anyhow::Result<()> {
|
fn number(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
s.emit_constant(match s.previous_token.token_type {
|
let number = &s.previous_token.lexeme;
|
||||||
TokenType::Number => Value::F64(s.previous_token.lexeme.parse()?),
|
let value = if let Some(expected_type) = expected_type {
|
||||||
_ => unimplemented!(), // TODO numeric types
|
match expected_type {
|
||||||
});
|
TokenType::I32 => Value::I32(number.parse()?),
|
||||||
|
TokenType::I64 => Value::I64(number.parse()?),
|
||||||
|
TokenType::U32 => Value::U32(number.parse()?),
|
||||||
|
TokenType::U64 => Value::U64(number.parse()?),
|
||||||
|
TokenType::F32 => Value::U32(number.parse()?),
|
||||||
|
TokenType::F64 => Value::U64(number.parse()?),
|
||||||
|
|
||||||
|
_ => {return Err(anyhow!("Invalid type: expected {} value, got {}({})", expected_type, &s.previous_token.token_type, number));}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let TokenType::Number = s.previous_token.token_type {
|
||||||
|
if number.contains('.'){
|
||||||
|
Value::F64(number.parse()?)
|
||||||
|
} else {
|
||||||
|
Value::I64(number.parse()?)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(anyhow!("I did not think this would happen"))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
s.emit_constant(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn literal(s: &mut Compiler) -> anyhow::Result<()> {
|
fn literal(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
|
if let Some(expected_type) = expected_type {
|
||||||
|
if discriminant(&expected_type) != discriminant(&s.previous_token.token_type) {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Cannot assign {:?} to {:?}",
|
||||||
|
s.previous_token.token_type,
|
||||||
|
expected_type
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
match s.previous_token.token_type {
|
match s.previous_token.token_type {
|
||||||
TokenType::False => s.emit_constant(Value::Bool(false)),
|
TokenType::False => s.emit_constant(Value::Bool(false)),
|
||||||
TokenType::True => s.emit_constant(Value::Bool(true)),
|
TokenType::True => s.emit_constant(Value::Bool(true)),
|
||||||
TokenType::String => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
TokenType::Text => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip(s: &mut Compiler) -> anyhow::Result<()> {
|
fn skip(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
// s.advance()
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn grouping(s: &mut Compiler) -> anyhow::Result<()> {
|
fn grouping(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
s.expression()?;
|
s.expression(None)?;
|
||||||
s.consume(TokenType::RightParen, "Expect ')' after expression.")
|
s.consume(TokenType::RightParen, "Expect ')' after expression.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(s: &mut Compiler) -> anyhow::Result<()> {
|
fn unary(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
let operator_type = s.previous_token.token_type;
|
let operator_type = s.previous_token.token_type;
|
||||||
|
|
||||||
s.parse_precedence(PREC_UNARY)?;
|
s.parse_precedence(PREC_UNARY, None)?;
|
||||||
|
|
||||||
match operator_type {
|
match operator_type {
|
||||||
TokenType::Minus => {
|
TokenType::Minus => {
|
||||||
|
|
@ -262,11 +337,11 @@ fn unary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
fn binary(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
let operator_type = &s.previous_token.token_type;
|
let operator_type = &s.previous_token.token_type;
|
||||||
debug!("operator {:?}", operator_type);
|
debug!("operator {:?}", operator_type);
|
||||||
let rule = get_rule(operator_type);
|
let rule = get_rule(operator_type);
|
||||||
s.parse_precedence(rule.precedence + 1)?;
|
s.parse_precedence(rule.precedence + 1, None)?;
|
||||||
match operator_type {
|
match operator_type {
|
||||||
TokenType::Plus => s.emit_byte(OP_ADD),
|
TokenType::Plus => s.emit_byte(OP_ADD),
|
||||||
TokenType::Minus => s.emit_byte(OP_SUBTRACT),
|
TokenType::Minus => s.emit_byte(OP_SUBTRACT),
|
||||||
|
|
@ -287,7 +362,7 @@ fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variable(s: &mut Compiler) -> anyhow::Result<()> {
|
fn variable(s: &mut Compiler, expected_type: Option<TokenType>) -> anyhow::Result<()> {
|
||||||
let index = s.identifier_constant(s.previous_token)?;
|
let index = s.identifier_constant(s.previous_token)?;
|
||||||
s.emit_bytes(OP_GET, index as u16);
|
s.emit_bytes(OP_GET, index as u16);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -309,7 +384,7 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
);
|
);
|
||||||
rules.insert(TokenType::Colon, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Colon, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Comma, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Comma, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::DateType, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Date, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Dot, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Dot, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Else, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Else, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Eof, Rule::new(Some(skip), None, PREC_NONE));
|
rules.insert(TokenType::Eof, Rule::new(Some(skip), None, PREC_NONE));
|
||||||
|
|
@ -334,8 +409,8 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
TokenType::GreaterGreater,
|
TokenType::GreaterGreater,
|
||||||
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
||||||
);
|
);
|
||||||
rules.insert(TokenType::I32Type, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::I32, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::I64Type, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::I64, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(
|
rules.insert(
|
||||||
TokenType::Identifier,
|
TokenType::Identifier,
|
||||||
Rule::new(Some(variable), None, PREC_NONE),
|
Rule::new(Some(variable), None, PREC_NONE),
|
||||||
|
|
@ -377,16 +452,16 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
rules.insert(TokenType::RightBracket, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::RightBracket, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Slash, Rule::new(None, Some(binary), PREC_FACTOR));
|
rules.insert(TokenType::Slash, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||||
rules.insert(TokenType::Star, Rule::new(None, Some(binary), PREC_FACTOR));
|
rules.insert(TokenType::Star, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||||
rules.insert(TokenType::String, Rule::new(Some(literal), None, PREC_NONE));
|
rules.insert(TokenType::Text, Rule::new(Some(literal), None, PREC_NONE));
|
||||||
rules.insert(
|
rules.insert(
|
||||||
TokenType::BitAnd,
|
TokenType::BitAnd,
|
||||||
Rule::new(None, Some(binary), PREC_BITAND),
|
Rule::new(None, Some(binary), PREC_BITAND),
|
||||||
);
|
);
|
||||||
rules.insert(TokenType::StringType, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::String, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Struct, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Struct, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::True, Rule::new(Some(literal), None, PREC_NONE));
|
rules.insert(TokenType::True, Rule::new(Some(literal), None, PREC_NONE));
|
||||||
rules.insert(TokenType::U32Type, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::U32, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::U64Type, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::U64, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::While, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::While, Rule::new(None, None, PREC_NONE));
|
||||||
|
|
||||||
rules
|
rules
|
||||||
|
|
@ -407,3 +482,19 @@ const PREC_FACTOR: usize = 11;
|
||||||
const PREC_UNARY: usize = 12;
|
const PREC_UNARY: usize = 12;
|
||||||
const PREC_CALL: usize = 13;
|
const PREC_CALL: usize = 13;
|
||||||
const PREC_PRIMARY: usize = 14;
|
const PREC_PRIMARY: usize = 14;
|
||||||
|
|
||||||
|
enum ValueType{
|
||||||
|
DateType,
|
||||||
|
BoolType,
|
||||||
|
CharType,
|
||||||
|
F32Type,
|
||||||
|
F64Type,
|
||||||
|
I32Type,
|
||||||
|
I64Type,
|
||||||
|
ObjectType,
|
||||||
|
U32Type,
|
||||||
|
U64Type,
|
||||||
|
StringType,
|
||||||
|
ListType,
|
||||||
|
MapType,
|
||||||
|
}
|
||||||
|
|
@ -3,27 +3,29 @@ use crate::tokens::TokenType;
|
||||||
pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
||||||
match lexeme {
|
match lexeme {
|
||||||
"and" => Some(TokenType::LogicalAnd),
|
"and" => Some(TokenType::LogicalAnd),
|
||||||
"bool" => Some(TokenType::BoolType),
|
"bool" => Some(TokenType::Bool),
|
||||||
"char" => Some(TokenType::CharType),
|
"char" => Some(TokenType::Char),
|
||||||
"date" => Some(TokenType::DateType),
|
"date" => Some(TokenType::Date),
|
||||||
"else" => Some(TokenType::Else),
|
"else" => Some(TokenType::Else),
|
||||||
"false" => Some(TokenType::False),
|
"false" => Some(TokenType::False),
|
||||||
|
"f32" => Some(TokenType::F32),
|
||||||
|
"f64" => Some(TokenType::F64),
|
||||||
"fn" => Some(TokenType::Fn),
|
"fn" => Some(TokenType::Fn),
|
||||||
"for" => Some(TokenType::For),
|
"for" => Some(TokenType::For),
|
||||||
"if" => Some(TokenType::If),
|
"if" => Some(TokenType::If),
|
||||||
"i32" => Some(TokenType::I32Type),
|
"i32" => Some(TokenType::I32),
|
||||||
"i64" => Some(TokenType::I64Type),
|
"i64" => Some(TokenType::I64),
|
||||||
"let" => Some(TokenType::Let),
|
"let" => Some(TokenType::Let),
|
||||||
"list" => Some(TokenType::ListType),
|
"list" => Some(TokenType::ListType),
|
||||||
"map" => Some(TokenType::MapType),
|
"map" => Some(TokenType::MapType),
|
||||||
"or" => Some(TokenType::LogicalOr),
|
"or" => Some(TokenType::LogicalOr),
|
||||||
"object" => Some(TokenType::ObjectType),
|
"object" => Some(TokenType::Object),
|
||||||
"print" => Some(TokenType::Print),
|
"print" => Some(TokenType::Print),
|
||||||
"struct" => Some(TokenType::Struct),
|
"struct" => Some(TokenType::Struct),
|
||||||
"string" => Some(TokenType::StringType),
|
"string" => Some(TokenType::String),
|
||||||
"true" => Some(TokenType::True),
|
"true" => Some(TokenType::True),
|
||||||
"u32" => Some(TokenType::U32Type),
|
"u32" => Some(TokenType::U32),
|
||||||
"u64" => Some(TokenType::U64Type),
|
"u64" => Some(TokenType::U64),
|
||||||
"while" => Some(TokenType::While),
|
"while" => Some(TokenType::While),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let chunk = crudlang::compiler::compile(
|
let chunk = crudlang::compiler::compile(
|
||||||
r#"let a = "hello " + 42
|
r#"let a:bool = 42"#,
|
||||||
print a print a
|
|
||||||
print a"#,
|
|
||||||
);
|
);
|
||||||
match chunk {
|
match chunk {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ impl Scanner {
|
||||||
let value: String = self.chars[self.start + 1..self.current - 1]
|
let value: String = self.chars[self.start + 1..self.current - 1]
|
||||||
.iter()
|
.iter()
|
||||||
.collect();
|
.collect();
|
||||||
self.add_token_with_value(TokenType::String, value);
|
self.add_token_with_value(TokenType::Text, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&self) -> char {
|
fn peek(&self) -> char {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub token_type: TokenType,
|
pub token_type: TokenType,
|
||||||
|
|
@ -27,11 +29,11 @@ pub(crate) enum TokenType {
|
||||||
BitAnd,
|
BitAnd,
|
||||||
BitOr,
|
BitOr,
|
||||||
BitXor,
|
BitXor,
|
||||||
BoolType,
|
Bool,
|
||||||
CharType,
|
Char,
|
||||||
Colon,
|
Colon,
|
||||||
Comma,
|
Comma,
|
||||||
DateType,
|
Date,
|
||||||
Dot,
|
Dot,
|
||||||
Else,
|
Else,
|
||||||
Eof,
|
Eof,
|
||||||
|
|
@ -39,6 +41,8 @@ pub(crate) enum TokenType {
|
||||||
Equal,
|
Equal,
|
||||||
EqualEqual,
|
EqualEqual,
|
||||||
Error,
|
Error,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
False,
|
False,
|
||||||
Fn,
|
Fn,
|
||||||
For,
|
For,
|
||||||
|
|
@ -46,8 +50,8 @@ pub(crate) enum TokenType {
|
||||||
GreaterEqual,
|
GreaterEqual,
|
||||||
GreaterGreater,
|
GreaterGreater,
|
||||||
Hash,
|
Hash,
|
||||||
I32Type,
|
I32,
|
||||||
I64Type,
|
I64,
|
||||||
If,
|
If,
|
||||||
Indent,
|
Indent,
|
||||||
Identifier,
|
Identifier,
|
||||||
|
|
@ -65,7 +69,7 @@ pub(crate) enum TokenType {
|
||||||
Minus,
|
Minus,
|
||||||
Not,
|
Not,
|
||||||
Number,
|
Number,
|
||||||
ObjectType,
|
Object,
|
||||||
Plus,
|
Plus,
|
||||||
Print,
|
Print,
|
||||||
Return,
|
Return,
|
||||||
|
|
@ -75,15 +79,84 @@ pub(crate) enum TokenType {
|
||||||
Semicolon,
|
Semicolon,
|
||||||
Slash,
|
Slash,
|
||||||
Star,
|
Star,
|
||||||
|
Text,
|
||||||
String,
|
String,
|
||||||
StringType,
|
|
||||||
Struct,
|
Struct,
|
||||||
True,
|
True,
|
||||||
U32Type,
|
U32,
|
||||||
U64Type,
|
U64,
|
||||||
While,
|
While,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TokenType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
TokenType::String => write!(f, "string"),
|
||||||
|
TokenType::Date => write!(f, "date"),
|
||||||
|
TokenType::Char => write!(f, "char"),
|
||||||
|
TokenType::I32 => write!(f, "i32"),
|
||||||
|
TokenType::I64 => write!(f, "i64"),
|
||||||
|
TokenType::U32 => write!(f, "u32"),
|
||||||
|
TokenType::U64 => write!(f, "u64"),
|
||||||
|
TokenType::F32 => write!(f, "f32"),
|
||||||
|
TokenType::F64 => write!(f, "f64"),
|
||||||
|
TokenType::Bool => write!(f, "bool"),
|
||||||
|
TokenType::Bang=> write!(f, "!"),
|
||||||
|
TokenType::BangEqual=> write!(f, "!="),
|
||||||
|
TokenType::BitAnd=> write!(f, "&"),
|
||||||
|
TokenType::BitOr=> write!(f, "|"),
|
||||||
|
TokenType::BitXor=> write!(f, "^"),
|
||||||
|
TokenType::Colon=> write!(f, ":"),
|
||||||
|
TokenType::Comma=> write!(f, ","),
|
||||||
|
TokenType::MapType => write!(f, "map"),
|
||||||
|
TokenType::ListType => write!(f, "list"),
|
||||||
|
TokenType::Dot => write!(f, "."),
|
||||||
|
TokenType::Else => write!(f, "else"),
|
||||||
|
TokenType::Eof => write!(f, "EOF"),
|
||||||
|
TokenType::Eol => write!(f, "EOL"),
|
||||||
|
TokenType::Equal => write!(f, "="),
|
||||||
|
TokenType::EqualEqual => write!(f, "=="),
|
||||||
|
TokenType::Error => write!(f, "error"),
|
||||||
|
TokenType::False => write!(f, "false"),
|
||||||
|
TokenType::Fn => write!(f, "fn"),
|
||||||
|
TokenType::For => write!(f, "for"),
|
||||||
|
TokenType::Greater => write!(f, ">"),
|
||||||
|
TokenType::GreaterEqual => write!(f, ">="),
|
||||||
|
TokenType::GreaterGreater => write!(f, ">>"),
|
||||||
|
TokenType::Hash => write!(f, "#"),
|
||||||
|
TokenType::If => write!(f, "if"),
|
||||||
|
TokenType::Indent => write!(f, "indent"),
|
||||||
|
TokenType::Identifier => write!(f, "identifier"),
|
||||||
|
TokenType::LeftBrace => write!(f, "{{"),
|
||||||
|
TokenType::LeftBracket => write!(f, "["),
|
||||||
|
TokenType::LeftParen => write!(f, "("),
|
||||||
|
TokenType::Less => write!(f, "<"),
|
||||||
|
TokenType::LessEqual => write!(f, "<="),
|
||||||
|
TokenType::LessLess => write!(f, "<<"),
|
||||||
|
TokenType::Let => write!(f, "let"),
|
||||||
|
TokenType::LogicalAnd => write!(f, "&&"),
|
||||||
|
TokenType::LogicalOr => write!(f, "||"),
|
||||||
|
TokenType::Minus => write!(f, "-"),
|
||||||
|
TokenType::Not => write!(f, "not"),
|
||||||
|
TokenType::Number => write!(f, "number"),
|
||||||
|
TokenType::Object => write!(f, "object"),
|
||||||
|
TokenType::Plus => write!(f, "+"),
|
||||||
|
TokenType::Print => write!(f, "print"),
|
||||||
|
TokenType::Return => write!(f, "return"),
|
||||||
|
TokenType::RightParen => write!(f, ")"),
|
||||||
|
TokenType::RightBrace => write!(f, "}}"),
|
||||||
|
TokenType::RightBracket => write!(f, "]"),
|
||||||
|
TokenType::Semicolon => write!(f, ";"),
|
||||||
|
TokenType::Slash => write!(f, "/"),
|
||||||
|
TokenType::Star => write!(f, "*"),
|
||||||
|
TokenType::Text => write!(f, "text"),
|
||||||
|
TokenType::Struct => write!(f, "struct"),
|
||||||
|
TokenType::True => write!(f, "true"),
|
||||||
|
TokenType::While => write!(f, "while"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Eq for TokenType {
|
impl Eq for TokenType {
|
||||||
|
|
||||||
}
|
}
|
||||||
17
src/vm.rs
17
src/vm.rs
|
|
@ -81,6 +81,13 @@ impl Vm {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
self.local_vars.insert(name, value);
|
self.local_vars.insert(name, value);
|
||||||
}
|
}
|
||||||
|
OP_DEF_I32 => {
|
||||||
|
let name = self.read_constant();
|
||||||
|
let value = self.pop();
|
||||||
|
if let Value::I32(v) = value {
|
||||||
|
self.local_vars.insert(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
OP_GET => {
|
OP_GET => {
|
||||||
let name = self.read_constant();
|
let name = self.read_constant();
|
||||||
let value = self.local_vars.get(&name).unwrap();
|
let value = self.local_vars.get(&name).unwrap();
|
||||||
|
|
@ -160,3 +167,13 @@ pub const OP_SHL: u16 = 24;
|
||||||
pub const OP_POP: u16 = 25;
|
pub const OP_POP: u16 = 25;
|
||||||
pub const OP_DEFINE: u16 = 26;
|
pub const OP_DEFINE: u16 = 26;
|
||||||
pub const OP_GET: u16 = 27;
|
pub const OP_GET: u16 = 27;
|
||||||
|
pub const OP_DEF_I32: u16 = 28;
|
||||||
|
pub const OP_DEF_I64: u16 = 29;
|
||||||
|
pub const OP_DEF_U32: u16 = 30;
|
||||||
|
pub const OP_DEF_DATE: u16 = 31;
|
||||||
|
pub const OP_DEF_STRING: u16 = 32;
|
||||||
|
pub const OP_DEF_CHAR: u16 = 33;
|
||||||
|
pub const OP_DEF_BOOL: u16 = 34;
|
||||||
|
pub const OP_DEF_LIST: u16 = 35;
|
||||||
|
pub const OP_DEF_MAP: u16 = 36;
|
||||||
|
pub const OP_DEF_OBJ: u16 = 37;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue