Compare commits
4 Commits
b7d7244cfa
...
6bfe840314
Author | SHA1 | Date | |
---|---|---|---|
6bfe840314 | |||
3475b55db5 | |||
4760eea8f4 | |||
71095deaa0 |
@ -18,6 +18,13 @@
|
|||||||
- Change REPL to execute code only after `;;` is found
|
- Change REPL to execute code only after `;;` is found
|
||||||
- Forward the code generated by the REPL to the PHP repl
|
- Forward the code generated by the REPL to the PHP repl
|
||||||
|
|
||||||
|
|
||||||
|
## v0.1.3
|
||||||
|
|
||||||
|
- [ ] Test semantic analysis
|
||||||
|
- [ ] Generate php code from current AST
|
||||||
|
|
||||||
|
|
||||||
## v0.1.2
|
## v0.1.2
|
||||||
|
|
||||||
- [x] Parse conditionals
|
- [x] Parse conditionals
|
||||||
|
@ -10,6 +10,11 @@ impl Transpilable for PExpresssion<'_> {
|
|||||||
Primary(p) => p.transpile(),
|
Primary(p) => p.transpile(),
|
||||||
Assignment(a) => a.transpile(),
|
Assignment(a) => a.transpile(),
|
||||||
FunctionCall(f) => f.transpile(),
|
FunctionCall(f) => f.transpile(),
|
||||||
|
BinaryOp(left, right, op) => {
|
||||||
|
let left_str = left.transpile();
|
||||||
|
let right_str = right.transpile();
|
||||||
|
format!("{} {} {}", left_str, op, right_str)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ pub enum PExpresssion<'a> {
|
|||||||
Primary(PPrimary<'a>),
|
Primary(PPrimary<'a>),
|
||||||
/// This comes from a THP binding
|
/// This comes from a THP binding
|
||||||
Assignment(PSimpleAssignment<'a>),
|
Assignment(PSimpleAssignment<'a>),
|
||||||
|
BinaryOp(Box<PExpresssion<'a>>, Box<PExpresssion<'a>>, &'a String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PSimpleAssignment<'a> {
|
pub struct PSimpleAssignment<'a> {
|
||||||
|
@ -36,7 +36,14 @@ impl<'a> PHPTransformable<'a> for Expression<'_> {
|
|||||||
PExpresssion::Primary(PPrimary::BoolLiteral(b.value == "true"))
|
PExpresssion::Primary(PPrimary::BoolLiteral(b.value == "true"))
|
||||||
}
|
}
|
||||||
Expression::UnaryOperator(_, _) => unimplemented!("transform unary op into php"),
|
Expression::UnaryOperator(_, _) => unimplemented!("transform unary op into php"),
|
||||||
Expression::BinaryOperator(_, _, _) => unimplemented!("transform binary op into php"),
|
Expression::BinaryOperator(left_expr, right_expr, op) => {
|
||||||
|
// For now assume that any THP operator directly maps to a PHP operator...
|
||||||
|
|
||||||
|
let left_value = left_expr.into_php_ast();
|
||||||
|
let right_value = right_expr.into_php_ast();
|
||||||
|
|
||||||
|
PExpresssion::BinaryOp(Box::new(left_value), Box::new(right_value), &op.value)
|
||||||
|
}
|
||||||
Expression::Array(_) => unimplemented!("transform array into php"),
|
Expression::Array(_) => unimplemented!("transform array into php"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ impl SemanticCheck for VariableBinding<'_> {
|
|||||||
return Err(econtainer);
|
return Err(econtainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.expression.check_semantics(scope)?;
|
||||||
|
|
||||||
// This gets the datatype of the assigned expression,
|
// This gets the datatype of the assigned expression,
|
||||||
// to compare it later with the declared datatype.
|
// to compare it later with the declared datatype.
|
||||||
let expression_datatype = self.expression.get_type(scope)?;
|
let expression_datatype = self.expression.get_type(scope)?;
|
||||||
|
171
src/semantic/checks/expression/funtion_call.rs
Normal file
171
src/semantic/checks/expression/funtion_call.rs
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
use crate::{
|
||||||
|
error_handling::{
|
||||||
|
error_messages::{SEMANTIC_MISMATCHED_ARGUMENT_COUNT, SEMANTIC_MISMATCHED_TYPES},
|
||||||
|
ErrorContainer, ErrorLabel,
|
||||||
|
},
|
||||||
|
semantic::{
|
||||||
|
impls::SemanticCheck,
|
||||||
|
symbol_table::SymbolTable,
|
||||||
|
types::{Type, Typed},
|
||||||
|
},
|
||||||
|
syntax::ast::{functions::FunctionCall, Positionable},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl SemanticCheck for FunctionCall<'_> {
|
||||||
|
fn check_semantics(
|
||||||
|
&self,
|
||||||
|
scope: &SymbolTable,
|
||||||
|
) -> Result<(), crate::error_handling::MistiError> {
|
||||||
|
let fun = &*self.function;
|
||||||
|
let arguments = &*self.arguments.arguments;
|
||||||
|
|
||||||
|
let function_datatype = fun.get_type(scope)?;
|
||||||
|
let Type::Function(parameters, _) = function_datatype else {
|
||||||
|
let (error_start, error_end) = fun.get_position();
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: format!(
|
||||||
|
"Expected this expression to be a function, found a {:?}",
|
||||||
|
function_datatype
|
||||||
|
),
|
||||||
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(econtainer);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check parameters length
|
||||||
|
if parameters.len() != arguments.len() {
|
||||||
|
let (error_start, error_end) = self.arguments.get_position();
|
||||||
|
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: format!(
|
||||||
|
"Expected {} arguments, got {}",
|
||||||
|
parameters.len(),
|
||||||
|
arguments.len(),
|
||||||
|
),
|
||||||
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(econtainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that each argument matches the required datatype
|
||||||
|
for i in 0..parameters.len() {
|
||||||
|
let parameter = ¶meters[i];
|
||||||
|
let argument = &arguments[i];
|
||||||
|
|
||||||
|
let argument_datatype = argument.get_type(scope)?;
|
||||||
|
if !argument_datatype.is_value(parameter) {
|
||||||
|
// The argument and the parameter have diferent types
|
||||||
|
let (error_start, error_end) = argument.get_position();
|
||||||
|
let label = ErrorLabel {
|
||||||
|
message: format!("Expected a {}, got {:?}", parameter, argument_datatype),
|
||||||
|
start: error_start,
|
||||||
|
end: error_end,
|
||||||
|
};
|
||||||
|
let econtainer = ErrorContainer {
|
||||||
|
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||||
|
error_offset: error_start,
|
||||||
|
labels: vec![label],
|
||||||
|
note: None,
|
||||||
|
help: None,
|
||||||
|
};
|
||||||
|
return Err(econtainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{
|
||||||
|
error_handling::error_messages::{
|
||||||
|
SEMANTIC_INVALID_REFERENCE, SEMANTIC_MISMATCHED_TYPES, SEMANTIC_MISSING_REFERENCE,
|
||||||
|
},
|
||||||
|
lexic::{get_tokens, token::Token},
|
||||||
|
semantic::{
|
||||||
|
impls::SemanticCheck,
|
||||||
|
symbol_table::SymbolTable,
|
||||||
|
types::{global::INT, Type},
|
||||||
|
},
|
||||||
|
syntax::{
|
||||||
|
ast::{functions::FunctionCall, Expression},
|
||||||
|
parseable::Parseable,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn t(i: &str) -> Vec<Token> {
|
||||||
|
get_tokens(&i.into()).unwrap()
|
||||||
|
}
|
||||||
|
fn exp<'a>(t: &'a Vec<Token>) -> FunctionCall<'a> {
|
||||||
|
let e = Expression::try_parse(t, 0).unwrap().0;
|
||||||
|
match e {
|
||||||
|
Expression::FunctionCall(f) => f,
|
||||||
|
_ => panic!("Expected to parse a function call"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_ref_not_exist() {
|
||||||
|
let b = t("my_fun()");
|
||||||
|
let expr = exp(&b);
|
||||||
|
|
||||||
|
let scope = SymbolTable::new();
|
||||||
|
|
||||||
|
let output = expr.check_semantics(&scope);
|
||||||
|
match output {
|
||||||
|
Ok(_) => panic!("Expected an error"),
|
||||||
|
Err(err) => {
|
||||||
|
assert_eq!(err.error_code, SEMANTIC_MISSING_REFERENCE);
|
||||||
|
assert_eq!(err.error_offset, 0);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(label.message, "Cannot find this identifier in this scope");
|
||||||
|
assert_eq!(label.start, 0);
|
||||||
|
assert_eq!(label.end, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_ref_not_a_function() {
|
||||||
|
let b = t("my_fun()");
|
||||||
|
let expr = exp(&b);
|
||||||
|
|
||||||
|
let scope = SymbolTable::new();
|
||||||
|
scope.insert(String::from("my_fun"), Type::Value(INT.into()));
|
||||||
|
|
||||||
|
let output = expr.check_semantics(&scope);
|
||||||
|
match output {
|
||||||
|
Ok(_) => panic!("Expected an error"),
|
||||||
|
Err(err) => {
|
||||||
|
assert_eq!(err.error_code, SEMANTIC_MISMATCHED_TYPES);
|
||||||
|
assert_eq!(err.error_offset, 0);
|
||||||
|
|
||||||
|
let label = &err.labels[0];
|
||||||
|
assert_eq!(
|
||||||
|
label.message,
|
||||||
|
"Expected this expression to be a function, found a `Int`"
|
||||||
|
);
|
||||||
|
assert_eq!(label.start, 0);
|
||||||
|
assert_eq!(label.end, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error_handling::{
|
error_handling::{
|
||||||
error_messages::{
|
error_messages::{COMPILER_TODO, SEMANTIC_INVALID_REFERENCE, SEMANTIC_MISMATCHED_TYPES},
|
||||||
COMPILER_TODO, SEMANTIC_INVALID_REFERENCE, SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
|
||||||
SEMANTIC_MISMATCHED_TYPES,
|
|
||||||
},
|
|
||||||
ErrorContainer, ErrorLabel, MistiError,
|
ErrorContainer, ErrorLabel, MistiError,
|
||||||
},
|
},
|
||||||
semantic::{
|
semantic::{
|
||||||
@ -14,90 +11,12 @@ use crate::{
|
|||||||
syntax::ast::{Expression, Positionable},
|
syntax::ast::{Expression, Positionable},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod funtion_call;
|
||||||
|
|
||||||
impl SemanticCheck for Expression<'_> {
|
impl SemanticCheck for Expression<'_> {
|
||||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::FunctionCall(f) => {
|
Expression::FunctionCall(f) => f.check_semantics(scope),
|
||||||
let fun = &*f.function;
|
|
||||||
let arguments = &*f.arguments.arguments;
|
|
||||||
|
|
||||||
let function_datatype = fun.get_type(scope)?;
|
|
||||||
match function_datatype {
|
|
||||||
Type::Function(parameters, _return_type) => {
|
|
||||||
// Check parameters length
|
|
||||||
if parameters.len() != arguments.len() {
|
|
||||||
let (error_start, error_end) = f.arguments.get_position();
|
|
||||||
|
|
||||||
let label = ErrorLabel {
|
|
||||||
message: format!(
|
|
||||||
"Expected {} arguments, got {}",
|
|
||||||
parameters.len(),
|
|
||||||
arguments.len(),
|
|
||||||
),
|
|
||||||
start: error_start,
|
|
||||||
end: error_end,
|
|
||||||
};
|
|
||||||
let econtainer = ErrorContainer {
|
|
||||||
error_code: SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
|
||||||
error_offset: error_start,
|
|
||||||
labels: vec![label],
|
|
||||||
note: None,
|
|
||||||
help: None,
|
|
||||||
};
|
|
||||||
return Err(econtainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that each argument matches the required datatype
|
|
||||||
for i in 0..parameters.len() {
|
|
||||||
let parameter = ¶meters[i];
|
|
||||||
let argument = &arguments[i];
|
|
||||||
|
|
||||||
let argument_datatype = argument.get_type(scope)?;
|
|
||||||
if !argument_datatype.is_value(parameter) {
|
|
||||||
// The argument and the parameter have diferent types
|
|
||||||
let (error_start, error_end) = argument.get_position();
|
|
||||||
let label = ErrorLabel {
|
|
||||||
message: format!(
|
|
||||||
"Expected a {}, got {:?}",
|
|
||||||
parameter, argument_datatype
|
|
||||||
),
|
|
||||||
start: error_start,
|
|
||||||
end: error_end,
|
|
||||||
};
|
|
||||||
let econtainer = ErrorContainer {
|
|
||||||
error_code: SEMANTIC_MISMATCHED_TYPES,
|
|
||||||
error_offset: error_start,
|
|
||||||
labels: vec![label],
|
|
||||||
note: None,
|
|
||||||
help: None,
|
|
||||||
};
|
|
||||||
return Err(econtainer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let (error_start, error_end) = fun.get_position();
|
|
||||||
let label = ErrorLabel {
|
|
||||||
message: format!(
|
|
||||||
"Expected a function type, got {:?}",
|
|
||||||
function_datatype
|
|
||||||
),
|
|
||||||
start: error_start,
|
|
||||||
end: error_end,
|
|
||||||
};
|
|
||||||
let econtainer = ErrorContainer {
|
|
||||||
error_code: SEMANTIC_MISMATCHED_TYPES,
|
|
||||||
error_offset: error_start,
|
|
||||||
labels: vec![label],
|
|
||||||
note: None,
|
|
||||||
help: None,
|
|
||||||
};
|
|
||||||
return Err(econtainer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// These are empty because they have nothing to check,
|
// These are empty because they have nothing to check,
|
||||||
// their existance alone is correct
|
// their existance alone is correct
|
||||||
Expression::Int(_) => Ok(()),
|
Expression::Int(_) => Ok(()),
|
||||||
@ -261,7 +180,7 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
let label = ErrorLabel {
|
let label = ErrorLabel {
|
||||||
message: format!(
|
message: format!(
|
||||||
"Expected a {}, got a {:?} on the right side of the {} operator",
|
"Expected a {}, got a {:?} on the right side of the {} operator",
|
||||||
op_params[1], left_expr_type, op.value
|
op_params[1], right_expr_type, op.value
|
||||||
),
|
),
|
||||||
start: error_start,
|
start: error_start,
|
||||||
end: error_end,
|
end: error_end,
|
||||||
@ -350,41 +269,22 @@ impl SemanticCheck for Expression<'_> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
lexic::token::Token,
|
lexic::{get_tokens, token::Token},
|
||||||
semantic::{impls::SemanticCheck, std::populate, symbol_table::SymbolTable},
|
semantic::{impls::SemanticCheck, std::populate, symbol_table::SymbolTable},
|
||||||
syntax::ast::{
|
syntax::{
|
||||||
|
ast::{
|
||||||
functions::{ArgumentsList, FunctionCall},
|
functions::{ArgumentsList, FunctionCall},
|
||||||
Expression,
|
Expression,
|
||||||
},
|
},
|
||||||
|
parseable::Parseable,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
fn t(i: &str) -> Vec<Token> {
|
||||||
fn should_error_on_undefined_symbol() {
|
get_tokens(&i.into()).unwrap()
|
||||||
// source code: `print()`
|
|
||||||
let expr_token = Token::new_identifier("print".into(), 0);
|
|
||||||
let expr_function = Expression::Identifier(&expr_token);
|
|
||||||
let arguments = ArgumentsList {
|
|
||||||
arguments: vec![],
|
|
||||||
paren_open_pos: 5,
|
|
||||||
paren_close_pos: 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
let expr = Expression::FunctionCall(FunctionCall {
|
|
||||||
function: Box::new(expr_function),
|
|
||||||
arguments: Box::new(arguments),
|
|
||||||
});
|
|
||||||
|
|
||||||
let scope = SymbolTable::new();
|
|
||||||
|
|
||||||
let output = expr.check_semantics(&scope);
|
|
||||||
match output {
|
|
||||||
Ok(_) => panic!("Expected an error"),
|
|
||||||
Err(err) => {
|
|
||||||
//assert_eq!(err.reason, "Cannot find `print` in this scope.");
|
|
||||||
assert_eq!(err.error_offset, 0);
|
|
||||||
//assert_eq!(err.error_end, 5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
fn exp<'a>(t: &'a Vec<Token>) -> Expression<'a> {
|
||||||
|
Expression::try_parse(t, 0).unwrap().0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
@ -7,7 +7,7 @@ use crate::{
|
|||||||
impl SemanticCheck for FunctionDeclaration<'_> {
|
impl SemanticCheck for FunctionDeclaration<'_> {
|
||||||
fn check_semantics(
|
fn check_semantics(
|
||||||
&self,
|
&self,
|
||||||
scope: &crate::semantic::symbol_table::SymbolTable,
|
scope: &SymbolTable,
|
||||||
) -> Result<(), crate::error_handling::MistiError> {
|
) -> Result<(), crate::error_handling::MistiError> {
|
||||||
let function_name = self.identifier.value.clone();
|
let function_name = self.identifier.value.clone();
|
||||||
|
|
||||||
|
@ -4,6 +4,10 @@ use super::symbol_table::SymbolTable;
|
|||||||
|
|
||||||
/// Allows this type to have it's semantics checked.
|
/// Allows this type to have it's semantics checked.
|
||||||
pub trait SemanticCheck {
|
pub trait SemanticCheck {
|
||||||
|
/// Checks the semantics of this AST node and performs typechecking
|
||||||
|
///
|
||||||
|
/// Types are provided by the Typed trait, because not every AST node
|
||||||
|
/// will have a defined type
|
||||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError>;
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,11 +2,21 @@
|
|||||||
//! by directly inserting the definitions into the
|
//! by directly inserting the definitions into the
|
||||||
//! Symbol Table
|
//! Symbol Table
|
||||||
|
|
||||||
use super::{symbol_table::SymbolTable, types::Type};
|
use super::{
|
||||||
|
symbol_table::SymbolTable,
|
||||||
|
types::{
|
||||||
|
global::{INT, STRING, VOID},
|
||||||
|
Type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/// Populates the symbol table with the stdlib
|
/// Populates the symbol table with the stdlib
|
||||||
pub fn populate(table: &mut SymbolTable) {
|
pub fn populate(table: &mut SymbolTable) {
|
||||||
// print: (String) -> (Void)
|
// print: (String) -> (Void)
|
||||||
let print_fn = Type::Function(vec!["String".into()], "Void".into());
|
let print_fn = Type::Function(vec![STRING.into()], VOID.into());
|
||||||
table.insert("print".into(), print_fn);
|
table.insert("print".into(), print_fn);
|
||||||
|
|
||||||
|
// + operator (Int, Int) -> Int
|
||||||
|
let plus_op = Type::Function(vec![INT.into(), INT.into()], INT.into());
|
||||||
|
table.insert("+".into(), plus_op);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ use crate::{
|
|||||||
use super::{Type, Typed};
|
use super::{Type, Typed};
|
||||||
|
|
||||||
impl Typed for Expression<'_> {
|
impl Typed for Expression<'_> {
|
||||||
/// Attempts to get the datatype for an expression.
|
|
||||||
fn get_type(&self, scope: &SymbolTable) -> Result<Type, MistiError> {
|
fn get_type(&self, scope: &SymbolTable) -> Result<Type, MistiError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Int(_) => Ok(Type::Value("Int".into())),
|
Expression::Int(_) => Ok(Type::Value("Int".into())),
|
||||||
@ -162,18 +161,16 @@ impl Typed for Expression<'_> {
|
|||||||
|
|
||||||
unreachable!("Illegal state: Found an unexpected unary operator during semantic analysis: {}", op.value);
|
unreachable!("Illegal state: Found an unexpected unary operator during semantic analysis: {}", op.value);
|
||||||
}
|
}
|
||||||
Expression::BinaryOperator(exp1, exp2, operator) => {
|
Expression::BinaryOperator(_, _, operator) => {
|
||||||
let t1 = exp1.get_type(scope)?;
|
match scope.get_type(&operator.value) {
|
||||||
let t2 = exp2.get_type(scope)?;
|
Some(Type::Function(_, return_type)) => Ok(Type::Value(return_type)),
|
||||||
|
Some(_) => {
|
||||||
// TODO: There's definitely a better way to do this
|
unreachable!(
|
||||||
// maybe store operators as functions?
|
"Compiler error: The operator {} was defined but it wasn't a function",
|
||||||
if operator.value == "+" && t1.is_value("Int") && t2.is_value("Int") {
|
operator.value
|
||||||
return Ok(Type::Value("Int".into()));
|
)
|
||||||
} else if operator.value == "-" && t1.is_value("Int") && t2.is_value("Int") {
|
|
||||||
return Ok(Type::Value("Int".into()));
|
|
||||||
}
|
}
|
||||||
|
None => {
|
||||||
let label = ErrorLabel {
|
let label = ErrorLabel {
|
||||||
message: format!("Unsupported binary operator"),
|
message: format!("Unsupported binary operator"),
|
||||||
// TODO: Fix positioning
|
// TODO: Fix positioning
|
||||||
@ -189,6 +186,8 @@ impl Typed for Expression<'_> {
|
|||||||
};
|
};
|
||||||
return Err(econtainer);
|
return Err(econtainer);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Expression::Array(arr) => {
|
Expression::Array(arr) => {
|
||||||
// The first expression found determines the
|
// The first expression found determines the
|
||||||
// type of the array
|
// type of the array
|
||||||
|
3
src/semantic/types/global.rs
Normal file
3
src/semantic/types/global.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub const STRING: &str = "String";
|
||||||
|
pub const INT: &str = "Int";
|
||||||
|
pub const VOID: &str = "Void";
|
@ -6,6 +6,7 @@ use crate::error_handling::MistiError;
|
|||||||
use super::symbol_table::SymbolTable;
|
use super::symbol_table::SymbolTable;
|
||||||
|
|
||||||
mod expression;
|
mod expression;
|
||||||
|
pub mod global;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@ -45,5 +46,9 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Typed {
|
pub trait Typed {
|
||||||
|
/// Returns the datatype of this value.
|
||||||
|
///
|
||||||
|
/// This function does not perform typechecking, it only returns a type.
|
||||||
|
/// Typeckecking is done by the trait SemanticCheck
|
||||||
fn get_type(&self, scope: &SymbolTable) -> Result<Type, MistiError>;
|
fn get_type(&self, scope: &SymbolTable) -> Result<Type, MistiError>;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::error_handling::MistiError;
|
use crate::error_handling::MistiError;
|
||||||
|
|
||||||
mod functions;
|
mod functions;
|
||||||
mod parseable;
|
pub mod parseable;
|
||||||
mod parsers;
|
mod parsers;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user