all found issues fixed. got rid of some stupid mistakes
This commit is contained in:
parent
c63cf3777f
commit
8234e9d50a
7 changed files with 156 additions and 135 deletions
|
|
@ -228,6 +228,9 @@ impl AstCompiler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn let_declaration(&mut self) -> Result<Statement, CompilerError> {
|
fn let_declaration(&mut self) -> Result<Statement, CompilerError> {
|
||||||
|
if self.peek().token_type.is_type(){
|
||||||
|
return Err(CompilerError::KeywordNotAllowedAsIdentifier(self.peek().token_type))
|
||||||
|
}
|
||||||
let name_token = self.consume(Identifier, Expected("variable name."))?;
|
let name_token = self.consume(Identifier, Expected("variable name."))?;
|
||||||
|
|
||||||
let declared_type = if self.check(Colon) {
|
let declared_type = if self.check(Colon) {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
use crate::ast_compiler::{Expression, Function, Statement};
|
use crate::ast_compiler::{Expression, Function, Statement};
|
||||||
use crate::chunk::Chunk;
|
use crate::chunk::Chunk;
|
||||||
|
use crate::errors::CompilerError;
|
||||||
use crate::tokens::TokenType;
|
use crate::tokens::TokenType;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vm::{OP_ADD, OP_AND, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_CHAR, OP_DEF_DATE, OP_DEF_F32, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRING, OP_DEF_STRUCT, OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_GET, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT, OP_DEF_U32};
|
use crate::vm::{
|
||||||
|
OP_ADD, OP_AND, OP_ASSIGN, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL,
|
||||||
|
OP_DEF_CHAR, OP_DEF_DATE, OP_DEF_F32, OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST,
|
||||||
|
OP_DEF_MAP, OP_DEF_STRING, OP_DEF_STRUCT, OP_DEF_U32, OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_GET,
|
||||||
|
OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_OR,
|
||||||
|
OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, OP_SUBTRACT,
|
||||||
|
};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::errors::CompilerError;
|
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
namespace: Option<&str>,
|
namespace: Option<&str>,
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
) -> Result<(),CompilerError> {
|
) -> Result<(), CompilerError> {
|
||||||
compile_name(ast, namespace, registry)
|
compile_name(ast, namespace, registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,9 +28,10 @@ pub(crate) fn compile_function(
|
||||||
let mut compiler = Compiler::new(&function.name.lexeme);
|
let mut compiler = Compiler::new(&function.name.lexeme);
|
||||||
for parm in &function.parameters {
|
for parm in &function.parameters {
|
||||||
let name = parm.name.lexeme.clone();
|
let name = parm.name.lexeme.clone();
|
||||||
let name_index = compiler.chunk.add_constant(Value::String(name.clone()));
|
let var_index = compiler.chunk.add_var(&parm.var_type, &parm.name.lexeme);
|
||||||
compiler.vars.insert(name, name_index);
|
|
||||||
compiler.emit_bytes(OP_DEFINE, name_index as u16);
|
compiler.vars.insert(name, var_index);
|
||||||
|
// compiler.emit_bytes(OP_DEFINE, name_index as u16);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(compiler.compile(&function.body, registry, namespace)?)
|
Ok(compiler.compile(&function.body, registry, namespace)?)
|
||||||
|
|
@ -34,11 +41,11 @@ pub(crate) fn compile_name(
|
||||||
ast: &Vec<Statement>,
|
ast: &Vec<Statement>,
|
||||||
namespace: Option<&str>,
|
namespace: Option<&str>,
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
) -> Result<(),CompilerError> {
|
) -> Result<(), CompilerError> {
|
||||||
let name=namespace.unwrap_or("main");
|
let name = namespace.unwrap_or("main");
|
||||||
let compiler = Compiler::new(name);
|
let compiler = Compiler::new(name);
|
||||||
let chunk = compiler.compile(ast, registry, name)?;
|
let chunk = compiler.compile(ast, registry, name)?;
|
||||||
let qname = if let Some(namespace) = namespace{
|
let qname = if let Some(namespace) = namespace {
|
||||||
format!("{}.{}", namespace, "main")
|
format!("{}.{}", namespace, "main")
|
||||||
} else {
|
} else {
|
||||||
"main".to_string()
|
"main".to_string()
|
||||||
|
|
@ -70,17 +77,6 @@ impl Compiler {
|
||||||
registry: &mut HashMap<String, Chunk>,
|
registry: &mut HashMap<String, Chunk>,
|
||||||
namespace: &str,
|
namespace: &str,
|
||||||
) -> Result<Chunk, CompilerError> {
|
) -> Result<Chunk, CompilerError> {
|
||||||
//TODO can likely be removed
|
|
||||||
for statement in ast {
|
|
||||||
if let Statement::FunctionStmt { function } = statement {
|
|
||||||
self.emit_constant(Value::String(format!(
|
|
||||||
"{}.{}",
|
|
||||||
namespace,
|
|
||||||
function.name.lexeme.clone()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for statement in ast {
|
for statement in ast {
|
||||||
self.compile_statement(statement, registry, namespace)?;
|
self.compile_statement(statement, registry, namespace)?;
|
||||||
}
|
}
|
||||||
|
|
@ -102,10 +98,10 @@ impl Compiler {
|
||||||
var_type,
|
var_type,
|
||||||
initializer,
|
initializer,
|
||||||
} => {
|
} => {
|
||||||
let name_index = self.chunk.add_constant(Value::String(name.lexeme.clone()));
|
let name_index = self.chunk.add_var(var_type, &name.lexeme);
|
||||||
self.vars.insert(name.lexeme.clone(), name_index);
|
self.vars.insert(name.lexeme.clone(), name_index);
|
||||||
self.compile_expression(namespace, initializer, registry)?;
|
self.compile_expression(namespace, initializer, registry)?;
|
||||||
self.define_variable(var_type, name_index, &initializer)?;
|
self.emit_bytes(OP_ASSIGN, name_index as u16);
|
||||||
}
|
}
|
||||||
Statement::PrintStmt { value } => {
|
Statement::PrintStmt { value } => {
|
||||||
self.compile_expression(namespace, value, registry)?;
|
self.compile_expression(namespace, value, registry)?;
|
||||||
|
|
@ -116,7 +112,7 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
Statement::FunctionStmt { function } => {
|
Statement::FunctionStmt { function } => {
|
||||||
let function_name = function.name.lexeme.clone();
|
let function_name = function.name.lexeme.clone();
|
||||||
self.emit_constant(Value::String(function_name.clone()));
|
// self.emit_constant(Value::String(function_name.clone()));
|
||||||
let compiled_function = compile_function(function, registry, namespace)?;
|
let compiled_function = compile_function(function, registry, namespace)?;
|
||||||
registry.insert(
|
registry.insert(
|
||||||
format!("{}.{}", self.chunk.name, function_name),
|
format!("{}.{}", self.chunk.name, function_name),
|
||||||
|
|
@ -140,7 +136,7 @@ impl Compiler {
|
||||||
Expression::FunctionCall {
|
Expression::FunctionCall {
|
||||||
name, arguments, ..
|
name, arguments, ..
|
||||||
} => {
|
} => {
|
||||||
let qname=format!("{}.{}", namespace, name);
|
let qname = format!("{}.{}", namespace, name);
|
||||||
let name_index = self
|
let name_index = self
|
||||||
.chunk
|
.chunk
|
||||||
.find_constant(&qname)
|
.find_constant(&qname)
|
||||||
|
|
@ -163,12 +159,14 @@ impl Compiler {
|
||||||
for expr in values {
|
for expr in values {
|
||||||
self.compile_expression(namespace, expr, registry)?;
|
self.compile_expression(namespace, expr, registry)?;
|
||||||
}
|
}
|
||||||
|
self.emit_bytes(OP_DEF_LIST, values.len() as u16);
|
||||||
}
|
}
|
||||||
Expression::Map { entries, .. } => {
|
Expression::Map { entries, .. } => {
|
||||||
for (key, value) in entries {
|
for (key, value) in entries {
|
||||||
self.compile_expression(namespace, key, registry)?;
|
self.compile_expression(namespace, key, registry)?;
|
||||||
self.compile_expression(namespace, value, registry)?;
|
self.compile_expression(namespace, value, registry)?;
|
||||||
}
|
}
|
||||||
|
self.emit_bytes(OP_DEF_MAP, entries.len() as u16);
|
||||||
}
|
}
|
||||||
Expression::Grouping { expression, .. } => {
|
Expression::Grouping { expression, .. } => {
|
||||||
self.compile_expression(namespace, expression, registry)?
|
self.compile_expression(namespace, expression, registry)?
|
||||||
|
|
@ -219,42 +217,6 @@ impl Compiler {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn define_variable(
|
|
||||||
&mut self,
|
|
||||||
var_type: &TokenType,
|
|
||||||
name_index: usize,
|
|
||||||
initializer: &Expression,
|
|
||||||
) -> Result<(), CompilerError> {
|
|
||||||
let def_op = match var_type {
|
|
||||||
TokenType::I32 => OP_DEF_I32,
|
|
||||||
TokenType::I64 => OP_DEF_I64,
|
|
||||||
TokenType::U32 => OP_DEF_U32,
|
|
||||||
TokenType::U64 => OP_DEF_I64,
|
|
||||||
TokenType::F32 => OP_DEF_F32,
|
|
||||||
TokenType::F64 => OP_DEF_F64,
|
|
||||||
TokenType::Date => OP_DEF_DATE,
|
|
||||||
TokenType::StringType => OP_DEF_STRING,
|
|
||||||
TokenType::Char => OP_DEF_CHAR,
|
|
||||||
TokenType::Bool => OP_DEF_BOOL,
|
|
||||||
TokenType::ListType => OP_DEF_LIST,
|
|
||||||
TokenType::MapType => OP_DEF_MAP,
|
|
||||||
TokenType::Object => OP_DEF_STRUCT,
|
|
||||||
_ => unimplemented!("{}", var_type),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.emit_bytes(def_op, name_index as u16);
|
|
||||||
match initializer {
|
|
||||||
Expression::List { values, .. } => {
|
|
||||||
self.emit_byte(values.len() as u16);
|
|
||||||
}
|
|
||||||
Expression::Map { entries, .. } => {
|
|
||||||
self.emit_byte(entries.len() as u16);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn emit_byte(&mut self, byte: u16) {
|
fn emit_byte(&mut self, byte: u16) {
|
||||||
self.chunk.add(byte, self.current_line);
|
self.chunk.add(byte, self.current_line);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/chunk.rs
10
src/chunk.rs
|
|
@ -1,5 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use crate::ast_compiler::Parameter;
|
use crate::ast_compiler::Parameter;
|
||||||
|
use crate::tokens::TokenType;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::vm::{
|
use crate::vm::{
|
||||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32,
|
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CALL, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_F32,
|
||||||
|
|
@ -14,7 +15,8 @@ pub struct Chunk {
|
||||||
pub code: Vec<u16>,
|
pub code: Vec<u16>,
|
||||||
pub constants: Vec<Value>,
|
pub constants: Vec<Value>,
|
||||||
lines: Vec<usize>,
|
lines: Vec<usize>,
|
||||||
object_defs: HashMap<String, Vec<Parameter>>
|
object_defs: HashMap<String, Vec<Parameter>>,
|
||||||
|
pub vars: Vec<(TokenType, String)>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
|
|
@ -38,6 +40,7 @@ impl Chunk {
|
||||||
constants: vec![],
|
constants: vec![],
|
||||||
lines: vec![],
|
lines: vec![],
|
||||||
object_defs: HashMap::new(),
|
object_defs: HashMap::new(),
|
||||||
|
vars: vec![]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,6 +54,11 @@ impl Chunk {
|
||||||
self.constants.len() - 1
|
self.constants.len() - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn add_var(&mut self, var_type: &TokenType, name: &str) -> usize {
|
||||||
|
self.vars.push((var_type.clone(), name.to_string()));
|
||||||
|
self.vars.len() - 1
|
||||||
|
}
|
||||||
|
|
||||||
pub (crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]){
|
pub (crate) fn add_object_def(&mut self, name: &str, fields: &[Parameter]){
|
||||||
self.object_defs.insert(name.to_string(), fields.to_vec());
|
self.object_defs.insert(name.to_string(), fields.to_vec());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,19 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_infer_type() {
|
fn infer_type() {
|
||||||
assert_eq!(run(r#"let a=1
|
assert_eq!(run(r#"let a=1
|
||||||
a"#), Ok(Value::I64(1)));
|
a"#), Ok(Value::I64(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_u32() {
|
fn define_u32() {
|
||||||
assert_eq!(run(r#"let a:u32=1
|
assert_eq!(run(r#"let a:u32=1
|
||||||
a"#), Ok(Value::U32(1)));
|
a"#), Ok(Value::U32(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_char() {
|
fn define_char() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run(r#"let a:char='a'
|
run(r#"let a:char='a'
|
||||||
a"#),
|
a"#),
|
||||||
|
|
@ -50,7 +50,7 @@ a"#),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_u32_invalid_value_negative() {
|
fn define_u32_invalid_value_negative() {
|
||||||
let r = compile("let a:u32=-1");
|
let r = compile("let a:u32=-1");
|
||||||
assert!(r.is_err());
|
assert!(r.is_err());
|
||||||
if let Err(e) = &r {
|
if let Err(e) = &r {
|
||||||
|
|
@ -62,7 +62,7 @@ a"#),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_u64_invalid_value_negative() {
|
fn define_u64_invalid_value_negative() {
|
||||||
let r = compile("let a:u64=-1");
|
let r = compile("let a:u64=-1");
|
||||||
assert!(r.is_err());
|
assert!(r.is_err());
|
||||||
if let Err(e) = &r {
|
if let Err(e) = &r {
|
||||||
|
|
@ -97,7 +97,7 @@ add_hello("world")"#,),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn object_definition() {
|
fn define_object() {
|
||||||
let r = compile(
|
let r = compile(
|
||||||
r#"
|
r#"
|
||||||
object Person:
|
object Person:
|
||||||
|
|
@ -120,7 +120,7 @@ object Person:
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn let_map() {
|
fn literal_map() {
|
||||||
let result = run(r#"{"name": "Dent", "age": 40 }"#);
|
let result = run(r#"{"name": "Dent", "age": 40 }"#);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
let result = result.unwrap();
|
let result = result.unwrap();
|
||||||
|
|
@ -131,8 +131,29 @@ object Person:
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.get(&Value::String("age".to_string())).unwrap(),
|
map.get(&Value::String("age".to_string())).unwrap(),
|
||||||
&Value::I32(40)
|
&Value::I64(40)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn define_map() {
|
||||||
|
let result = run(r#"let m = {"name": "Dent"}
|
||||||
|
m"#);
|
||||||
|
|
||||||
|
let result = result.unwrap();
|
||||||
|
if let Value::Map(map) = result {
|
||||||
|
assert_eq!(
|
||||||
|
map.get(&Value::String("name".to_string())).unwrap(),
|
||||||
|
&Value::String("Dent".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn keyword_error(){
|
||||||
|
let result = run(r#"let map = {"name": "Dent"}"#);
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!("'map' is a keyword. You cannot use it as an identifier",result.unwrap_err().to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use thiserror::Error;
|
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
|
@ -11,7 +11,6 @@ pub enum Error {
|
||||||
Platform(String),
|
Platform(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
pub enum CompilerError {
|
pub enum CompilerError {
|
||||||
#[error("Compilation failed")]
|
#[error("Compilation failed")]
|
||||||
|
|
@ -21,7 +20,7 @@ pub enum CompilerError {
|
||||||
#[error("Expected {0}")]
|
#[error("Expected {0}")]
|
||||||
Expected(&'static str),
|
Expected(&'static str),
|
||||||
#[error("unexpected indent level {0} vs expected {1}")]
|
#[error("unexpected indent level {0} vs expected {1}")]
|
||||||
UnexpectedIndent(usize,usize),
|
UnexpectedIndent(usize, usize),
|
||||||
#[error("Type mismatch at line {0}: {1}")]
|
#[error("Type mismatch at line {0}: {1}")]
|
||||||
TypeError(usize, Box<CompilerError>),
|
TypeError(usize, Box<CompilerError>),
|
||||||
#[error("Uninitialized variables are not allowed.")]
|
#[error("Uninitialized variables are not allowed.")]
|
||||||
|
|
@ -39,7 +38,9 @@ pub enum CompilerError {
|
||||||
#[error("Illegal char length for {0} at line {1}")]
|
#[error("Illegal char length for {0} at line {1}")]
|
||||||
IllegalCharLength(String, usize),
|
IllegalCharLength(String, usize),
|
||||||
#[error("Unexpected type {0}")]
|
#[error("Unexpected type {0}")]
|
||||||
UnexpectedType(TokenType)
|
UnexpectedType(TokenType),
|
||||||
|
#[error("'{0}' is a keyword. You cannot use it as an identifier")]
|
||||||
|
KeywordNotAllowedAsIdentifier(TokenType),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
|
@ -58,4 +59,6 @@ pub enum ValueError {
|
||||||
CannotAnd(&'static str),
|
CannotAnd(&'static str),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Some(&'static str),
|
Some(&'static str),
|
||||||
}
|
#[error("Illegal cast")]
|
||||||
|
IllegalCast,
|
||||||
|
}
|
||||||
|
|
|
||||||
52
src/value.rs
52
src/value.rs
|
|
@ -1,10 +1,10 @@
|
||||||
|
use crate::errors::ValueError;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
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::errors::ValueError;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Object {
|
pub struct Object {
|
||||||
|
|
@ -32,6 +32,56 @@ pub enum Value {
|
||||||
Void,
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn cast_u32(self) -> Result<Self, ValueError> {
|
||||||
|
match self {
|
||||||
|
Value::U32(v) => Ok(Value::U32(v)),
|
||||||
|
Value::U64(v) => Ok(Value::U32(v as u32)),
|
||||||
|
Value::I32(v) => Ok(Value::U32(v as u32)),
|
||||||
|
Value::I64(v) => Ok(Value::U32(v as u32)),
|
||||||
|
Value::F32(v) => Ok(Value::U32(v as u32)),
|
||||||
|
Value::F64(v) => Ok(Value::U32(v as u32)),
|
||||||
|
_ => Err(ValueError::IllegalCast),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast_u64(self) -> Result<Self, ValueError> {
|
||||||
|
match self {
|
||||||
|
Value::U32(v) => Ok(Value::U64(v as u64)),
|
||||||
|
Value::U64(v) => Ok(Value::U64(v)),
|
||||||
|
Value::I32(v) => Ok(Value::U64(v as u64)),
|
||||||
|
Value::I64(v) => Ok(Value::U64(v as u64)),
|
||||||
|
Value::F32(v) => Ok(Value::U64(v as u64)),
|
||||||
|
Value::F64(v) => Ok(Value::U64(v as u64)),
|
||||||
|
_ => Err(ValueError::IllegalCast),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast_i32(self) -> Result<Self, ValueError> {
|
||||||
|
match self {
|
||||||
|
Value::U32(v) => Ok(Value::I32(v as i32)),
|
||||||
|
Value::U64(v) => Ok(Value::I32(v as i32)),
|
||||||
|
Value::I32(v) => Ok(Value::I32(v)),
|
||||||
|
Value::I64(v) => Ok(Value::I32(v as i32)),
|
||||||
|
Value::F32(v) => Ok(Value::I32(v as i32)),
|
||||||
|
Value::F64(v) => Ok(Value::I32(v as i32)),
|
||||||
|
_ => Err(ValueError::IllegalCast),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cast_f32(self) -> Result<Self, ValueError> {
|
||||||
|
match self {
|
||||||
|
Value::U32(v) => Ok(Value::F32(v as f32)),
|
||||||
|
Value::U64(v) => Ok(Value::F32(v as f32)),
|
||||||
|
Value::I32(v) => Ok(Value::F32(v as f32)),
|
||||||
|
Value::I64(v) => Ok(Value::F32(v as f32)),
|
||||||
|
Value::F32(v) => Ok(Value::F32(v)),
|
||||||
|
Value::F64(v) => Ok(Value::F32(v as f32)),
|
||||||
|
_ => Err(ValueError::IllegalCast),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Into<Value> for i32 {
|
impl Into<Value> for i32 {
|
||||||
fn into(self) -> Value {
|
fn into(self) -> Value {
|
||||||
Value::I32(self)
|
Value::I32(self)
|
||||||
|
|
|
||||||
94
src/vm.rs
94
src/vm.rs
|
|
@ -4,6 +4,7 @@ use crate::errors::{RuntimeError, ValueError};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
use crate::tokens::TokenType;
|
||||||
|
|
||||||
macro_rules! define_var {
|
macro_rules! define_var {
|
||||||
($self:ident, $variant:ident, $chunk:ident) => {{
|
($self:ident, $variant:ident, $chunk:ident) => {{
|
||||||
|
|
@ -40,7 +41,7 @@ pub fn interpret(registry: &HashMap<String, Chunk>, function: &str) -> Result<Va
|
||||||
error_occurred: false,
|
error_occurred: false,
|
||||||
registry,
|
registry,
|
||||||
};
|
};
|
||||||
vm.run(&chunk, vec![])
|
vm.run(&chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str) -> Result<Value, RuntimeError> {
|
pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str) -> Result<Value, RuntimeError> {
|
||||||
|
|
@ -52,7 +53,7 @@ pub async fn interpret_async(registry: &HashMap<String, Chunk>, function: &str)
|
||||||
error_occurred: false,
|
error_occurred: false,
|
||||||
registry,
|
registry,
|
||||||
};
|
};
|
||||||
vm.run(&chunk, vec![])
|
vm.run(&chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
|
|
@ -63,14 +64,20 @@ pub fn interpret_function(chunk: &Chunk, args: Vec<Value>) -> Result<Value, Runt
|
||||||
error_occurred: false,
|
error_occurred: false,
|
||||||
registry: &HashMap::new(),
|
registry: &HashMap::new(),
|
||||||
};
|
};
|
||||||
vm.run(chunk, args)
|
|
||||||
|
vm.run_function(chunk, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Vm<'a> {
|
impl<'a> Vm<'a> {
|
||||||
fn run(&mut self, chunk: &Chunk, args: Vec<Value>) -> Result<Value, RuntimeError> {
|
fn run_function(&mut self, chunk: &Chunk, mut args: Vec<Value>) -> Result<Value, RuntimeError> {
|
||||||
for arg in args {
|
// arguments -> locals
|
||||||
self.push(arg);
|
for (_,name) in chunk.vars.iter() {
|
||||||
|
self.local_vars.insert(name.clone(), args.remove(0));
|
||||||
}
|
}
|
||||||
|
self.run(&chunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(&mut self, chunk: &Chunk) -> Result<Value, RuntimeError> {
|
||||||
loop {
|
loop {
|
||||||
if self.error_occurred {
|
if self.error_occurred {
|
||||||
return Err(Something);
|
return Err(Something);
|
||||||
|
|
@ -131,64 +138,30 @@ impl<'a> Vm<'a> {
|
||||||
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_name(chunk);
|
|
||||||
let value = self.pop();
|
|
||||||
let value = match value{
|
|
||||||
Value::I32(v) => Value::I32(v),
|
|
||||||
Value::I64(v) => Value::I32(v as i32),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
self.local_vars.insert(name, value);
|
|
||||||
}
|
|
||||||
OP_DEF_I64 => define_var!(self, I64, chunk),
|
|
||||||
OP_DEF_U32 => {
|
|
||||||
let name = self.read_name(chunk);
|
|
||||||
let value = self.pop();
|
|
||||||
let value = match value{
|
|
||||||
Value::U32(v) => Value::U32(v),
|
|
||||||
Value::I64(v) => Value::U32(v as u32),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
self.local_vars.insert(name, value);
|
|
||||||
}
|
|
||||||
OP_DEF_U64 => {
|
|
||||||
let name = self.read_name(chunk);
|
|
||||||
let value = self.pop();
|
|
||||||
let value = match value{
|
|
||||||
Value::U64(v) => Value::U64(v),
|
|
||||||
Value::I64(v) => Value::U64(v as u64),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
self.local_vars.insert(name, value);
|
|
||||||
}
|
|
||||||
OP_DEF_F32 => {
|
|
||||||
let name = self.read_name(chunk);
|
|
||||||
let value = self.pop();
|
|
||||||
let value = match value{
|
|
||||||
Value::F32(v) => Value::F32(v),
|
|
||||||
Value::F64(v) => Value::F32(v as f32),
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
self.local_vars.insert(name, value);
|
|
||||||
}
|
|
||||||
OP_DEF_F64 => define_var!(self, F64, chunk),
|
|
||||||
OP_DEF_STRING => define_var!(self, String, chunk),
|
|
||||||
OP_DEF_CHAR => define_var!(self, Char, chunk),
|
|
||||||
OP_DEF_BOOL => define_var!(self, Bool, chunk),
|
|
||||||
OP_DEF_DATE => define_var!(self, Date, chunk),
|
|
||||||
OP_DEF_LIST => {
|
OP_DEF_LIST => {
|
||||||
let name = self.read_name(chunk);
|
|
||||||
let len = self.read(chunk);
|
let len = self.read(chunk);
|
||||||
let mut list = vec![];
|
let mut list = vec![];
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
list.push(value);
|
list.push(value);
|
||||||
}
|
}
|
||||||
self.local_vars.insert(name, Value::List(list));
|
list.reverse();
|
||||||
|
self.push(Value::List(list));
|
||||||
|
}
|
||||||
|
OP_ASSIGN=>{
|
||||||
|
let index = self.read(chunk);
|
||||||
|
let (var_type, name) = chunk.vars.get(index).unwrap();
|
||||||
|
let value = self.pop();
|
||||||
|
let value = match var_type{
|
||||||
|
TokenType::U32 => value.cast_u32()?,
|
||||||
|
TokenType::U64 => value.cast_u64()?,
|
||||||
|
TokenType::F32 => value.cast_f32()?,
|
||||||
|
TokenType::I32 => value.cast_i32()?,
|
||||||
|
_ => value,
|
||||||
|
};
|
||||||
|
self.local_vars.insert(name.to_string(), value);
|
||||||
}
|
}
|
||||||
OP_DEF_MAP => {
|
OP_DEF_MAP => {
|
||||||
let name = self.read_name(chunk);
|
|
||||||
let len = self.read(chunk);
|
let len = self.read(chunk);
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
|
|
@ -196,12 +169,13 @@ impl<'a> Vm<'a> {
|
||||||
let key = self.pop();
|
let key = self.pop();
|
||||||
map.insert(key, value);
|
map.insert(key, value);
|
||||||
}
|
}
|
||||||
self.local_vars.insert(name, Value::Map(map));
|
self.push(Value::Map(map));
|
||||||
}
|
}
|
||||||
OP_GET => {
|
OP_GET => {
|
||||||
let name = self.read_name(chunk);
|
let var_index = self.read(chunk);
|
||||||
let value = self.local_vars.get(&name).unwrap();
|
let (_,name_index)= chunk.vars.get(var_index).unwrap();
|
||||||
self.push(value.clone()); // not happy
|
let value = self.local_vars.get(name_index).unwrap();
|
||||||
|
self.push(value.clone()); // not happy , take ownership, no clone
|
||||||
debug!("after get {:?}", self.stack);
|
debug!("after get {:?}", self.stack);
|
||||||
}
|
}
|
||||||
OP_CALL => {
|
OP_CALL => {
|
||||||
|
|
@ -309,4 +283,4 @@ pub const OP_DEF_MAP: u16 = 37;
|
||||||
pub const OP_DEF_STRUCT: u16 = 38;
|
pub const OP_DEF_STRUCT: u16 = 38;
|
||||||
pub const OP_DEF_F32: u16 = 39;
|
pub const OP_DEF_F32: u16 = 39;
|
||||||
pub const OP_DEF_F64: u16 = 40;
|
pub const OP_DEF_F64: u16 = 40;
|
||||||
// pub const OP_NEW_LIST: u16 = 40;
|
pub const OP_ASSIGN: u16 = 41;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue