adding map access was easy
This commit is contained in:
parent
cbc7f6ce7a
commit
6f4824efac
6 changed files with 41 additions and 40 deletions
|
|
@ -520,35 +520,39 @@ impl AstCompiler {
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
let get = (match &operand {
|
let get = (match &operand {
|
||||||
Expression::Map { .. } => MapGet {
|
Expression::Map { .. } => MapGet {
|
||||||
|
map: Box::new(operand),
|
||||||
key: Box::new(index),
|
key: Box::new(index),
|
||||||
},
|
},
|
||||||
Expression::List { .. } => ListGet {
|
Expression::List { .. } => ListGet {
|
||||||
list: Box::new(operand),
|
list: Box::new(operand),
|
||||||
index: Box::new(index),
|
index: Box::new(index),
|
||||||
},
|
},
|
||||||
Variable { var_type, .. } => {
|
Variable { var_type, .. } => match var_type {
|
||||||
if var_type == &ListType {
|
ListType => ListGet {
|
||||||
ListGet {
|
|
||||||
list: Box::new(operand),
|
list: Box::new(operand),
|
||||||
index: Box::new(index),
|
index: Box::new(index),
|
||||||
}
|
},
|
||||||
} else {
|
MapType => MapGet {
|
||||||
|
map: Box::new(operand),
|
||||||
|
key: Box::new(index),
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
return Err(self.raise(CompilerError::IllegalTypeToIndex(var_type.to_string())));
|
return Err(self.raise(CompilerError::IllegalTypeToIndex(var_type.to_string())));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => return Err(self.raise(CompilerError::IllegalTypeToIndex("Unknown".to_string()))),
|
_ => return Err(self.raise(CompilerError::IllegalTypeToIndex("Unknown".to_string()))),
|
||||||
});
|
});
|
||||||
self.consume(RightBracket, Expected("']' after index."))?;
|
self.consume(RightBracket, Expected("']' after index."))?;
|
||||||
Ok(get)
|
Ok(get)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// work in progress
|
||||||
fn field(
|
fn field(
|
||||||
&mut self,
|
&mut self,
|
||||||
operand: Expression,
|
_operand: Expression,
|
||||||
index: Token,
|
index: Token,
|
||||||
) -> Result<Expression, CompilerErrorAtLine> {
|
) -> Result<Expression, CompilerErrorAtLine> {
|
||||||
//TODO?
|
Ok(FieldGet {
|
||||||
Ok(Expression::FieldGet {
|
|
||||||
field: index.lexeme.clone(),
|
field: index.lexeme.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -635,7 +639,7 @@ impl AstCompiler {
|
||||||
&self.previous().lexeme,
|
&self.previous().lexeme,
|
||||||
"%Y-%m-%d %H:%M:%S%.3f %z",
|
"%Y-%m-%d %H:%M:%S%.3f %z",
|
||||||
)
|
)
|
||||||
.map_err(|e| self.raise(ParseError(self.previous().lexeme.clone())))?
|
.map_err(|_| self.raise(ParseError(self.previous().lexeme.clone())))?
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
@ -945,6 +949,7 @@ pub enum Expression {
|
||||||
value: Box<Expression>,
|
value: Box<Expression>,
|
||||||
},
|
},
|
||||||
MapGet {
|
MapGet {
|
||||||
|
map: Box<Expression>,
|
||||||
key: Box<Expression>,
|
key: Box<Expression>,
|
||||||
},
|
},
|
||||||
ListGet {
|
ListGet {
|
||||||
|
|
|
||||||
|
|
@ -102,17 +102,11 @@ impl Compiler {
|
||||||
self.current_line = statement.line();
|
self.current_line = statement.line();
|
||||||
match statement {
|
match statement {
|
||||||
Statement::VarStmt {
|
Statement::VarStmt {
|
||||||
name,
|
name, initializer, ..
|
||||||
var_type,
|
|
||||||
initializer,
|
|
||||||
} => {
|
} => {
|
||||||
let name = name.lexeme.as_str();
|
let name = name.lexeme.as_str();
|
||||||
let var = symbols.get(name);
|
let var = symbols.get(name);
|
||||||
if let Some(Symbol::Variable {
|
if let Some(Symbol::Variable { var_type, .. }) = var {
|
||||||
var_type,
|
|
||||||
..
|
|
||||||
}) = var
|
|
||||||
{
|
|
||||||
let inferred_type = infer_type(initializer, symbols);
|
let inferred_type = infer_type(initializer, symbols);
|
||||||
let calculated_type = calculate_type(var_type, &inferred_type)
|
let calculated_type = calculate_type(var_type, &inferred_type)
|
||||||
.map_err(|e| CompilerErrorAtLine::raise(e, statement.line()))?;
|
.map_err(|e| CompilerErrorAtLine::raise(e, statement.line()))?;
|
||||||
|
|
@ -189,13 +183,7 @@ impl Compiler {
|
||||||
.find_constant(&name)
|
.find_constant(&name)
|
||||||
.unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string())));
|
.unwrap_or_else(|| self.chunk.add_constant(Value::String(name.to_string())));
|
||||||
let function = symbols.get(name);
|
let function = symbols.get(name);
|
||||||
if let Some(Symbol::Function {
|
if let Some(Symbol::Function { parameters, .. }) = function {
|
||||||
name,
|
|
||||||
parameters,
|
|
||||||
return_type,
|
|
||||||
body,
|
|
||||||
}) = function
|
|
||||||
{
|
|
||||||
for parameter in parameters {
|
for parameter in parameters {
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
if let NamedParameter { name, .. } = argument {
|
if let NamedParameter { name, .. } = argument {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use crate::{compile, run};
|
use crate::{compile, run};
|
||||||
use chrono::{DateTime};
|
use chrono::DateTime;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literal_int() {
|
fn literal_int() {
|
||||||
|
|
@ -42,8 +42,11 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn index_in_list_as_var() {
|
fn index_in_list_as_var() {
|
||||||
assert_eq!(run(r#"let a:list = ["abc","def"]
|
assert_eq!(
|
||||||
a[1]"#), Ok(Value::String("def".into())))
|
run(r#"let a:list = ["abc","def"]
|
||||||
|
a[1]"#),
|
||||||
|
Ok(Value::String("def".into()))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -163,7 +166,7 @@ object Person:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn define_map() {
|
fn assign_map() {
|
||||||
let result = run(r#"let m = {"name": "Dent"}
|
let result = run(r#"let m = {"name": "Dent"}
|
||||||
m"#);
|
m"#);
|
||||||
|
|
||||||
|
|
@ -176,6 +179,17 @@ m"#);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn access_map() {
|
||||||
|
let result = run(r#"let m = {"name": "Dent"}
|
||||||
|
m["name"]"#);
|
||||||
|
|
||||||
|
let result = result.unwrap();
|
||||||
|
if let Value::String(v) = result {
|
||||||
|
assert_eq!(v.as_str(), "Dent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn keyword_error() {
|
fn keyword_error() {
|
||||||
let result = run(r#"let map = {"name": "Dent"}"#);
|
let result = run(r#"let map = {"name": "Dent"}"#);
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,6 @@ pub fn start(registry: Arc<ArcSwap<HashMap<String, Chunk>>>) -> Result<(), CrudL
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
// println!("-- Crudlang -- REPL exited");
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_endpoints(registry: Arc<HashMap<String, Chunk>>) {
|
fn list_endpoints(registry: Arc<HashMap<String, Chunk>>) {
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,7 @@ fn make_qname(path: &str, name: &Token) -> String {
|
||||||
pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol>) {
|
pub fn build(path: &str, ast: &[Statement], symbols: &mut HashMap<String, Symbol>) {
|
||||||
for statement in ast {
|
for statement in ast {
|
||||||
match statement {
|
match statement {
|
||||||
Statement::VarStmt {
|
Statement::VarStmt { name, var_type, .. } => {
|
||||||
name,
|
|
||||||
var_type,
|
|
||||||
initializer,
|
|
||||||
} => {
|
|
||||||
let key = make_qname(path, name);
|
let key = make_qname(path, name);
|
||||||
if !symbols.contains_key(&key) {
|
if !symbols.contains_key(&key) {
|
||||||
// surely there's a better way to do this?
|
// surely there's a better way to do this?
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::errors::ValueError;
|
use crate::errors::ValueError;
|
||||||
use chrono::{DateTime, Local, 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};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue