mirror of
https://github.com/edg-l/edlang.git
synced 2024-11-23 00:18:24 +00:00
better
This commit is contained in:
parent
bd93a7b313
commit
53e3e4dcd5
246
out
Normal file
246
out
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
Program {
|
||||||
|
statements: [
|
||||||
|
Struct(
|
||||||
|
Struct {
|
||||||
|
name: "Hello",
|
||||||
|
fields: [
|
||||||
|
StructField {
|
||||||
|
ident: "x",
|
||||||
|
type_exp: Integer {
|
||||||
|
bits: 32,
|
||||||
|
signed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
StructField {
|
||||||
|
ident: "y",
|
||||||
|
type_exp: Integer {
|
||||||
|
bits: 32,
|
||||||
|
signed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Function(
|
||||||
|
Function {
|
||||||
|
name: "test",
|
||||||
|
params: [
|
||||||
|
Parameter {
|
||||||
|
ident: "x",
|
||||||
|
type_exp: Other {
|
||||||
|
id: "Hello",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: [
|
||||||
|
Return(
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
return_type: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Function(
|
||||||
|
Function {
|
||||||
|
name: "works",
|
||||||
|
params: [
|
||||||
|
Parameter {
|
||||||
|
ident: "x",
|
||||||
|
type_exp: Integer {
|
||||||
|
bits: 64,
|
||||||
|
signed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
body: [
|
||||||
|
Let {
|
||||||
|
name: "z",
|
||||||
|
value: Literal(
|
||||||
|
Integer {
|
||||||
|
value: "0",
|
||||||
|
bits: None,
|
||||||
|
signed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
value_type: None,
|
||||||
|
span: (
|
||||||
|
107,
|
||||||
|
117,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
If {
|
||||||
|
condition: BinaryOp(
|
||||||
|
Literal(
|
||||||
|
Integer {
|
||||||
|
value: "2",
|
||||||
|
bits: None,
|
||||||
|
signed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Eq,
|
||||||
|
Variable {
|
||||||
|
name: Spanned {
|
||||||
|
span: (
|
||||||
|
130,
|
||||||
|
131,
|
||||||
|
),
|
||||||
|
value: "x",
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
body: [
|
||||||
|
Mutate {
|
||||||
|
name: "z",
|
||||||
|
value: BinaryOp(
|
||||||
|
Variable {
|
||||||
|
name: Spanned {
|
||||||
|
span: (
|
||||||
|
146,
|
||||||
|
147,
|
||||||
|
),
|
||||||
|
value: "x",
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
Mul,
|
||||||
|
Literal(
|
||||||
|
Integer {
|
||||||
|
value: "2",
|
||||||
|
bits: None,
|
||||||
|
signed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
value_type: None,
|
||||||
|
span: (
|
||||||
|
142,
|
||||||
|
152,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
else_body: Some(
|
||||||
|
[
|
||||||
|
Mutate {
|
||||||
|
name: "z",
|
||||||
|
value: BinaryOp(
|
||||||
|
Variable {
|
||||||
|
name: Spanned {
|
||||||
|
span: (
|
||||||
|
178,
|
||||||
|
179,
|
||||||
|
),
|
||||||
|
value: "x",
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
Mul,
|
||||||
|
Literal(
|
||||||
|
Integer {
|
||||||
|
value: "3",
|
||||||
|
bits: None,
|
||||||
|
signed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
value_type: None,
|
||||||
|
span: (
|
||||||
|
174,
|
||||||
|
184,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Return(
|
||||||
|
Some(
|
||||||
|
Variable {
|
||||||
|
name: Spanned {
|
||||||
|
span: (
|
||||||
|
202,
|
||||||
|
203,
|
||||||
|
),
|
||||||
|
value: "z",
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
return_type: Some(
|
||||||
|
Integer {
|
||||||
|
bits: 64,
|
||||||
|
signed: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Function(
|
||||||
|
Function {
|
||||||
|
name: "main",
|
||||||
|
params: [],
|
||||||
|
body: [
|
||||||
|
Let {
|
||||||
|
name: "y",
|
||||||
|
value: Literal(
|
||||||
|
Integer {
|
||||||
|
value: "2",
|
||||||
|
bits: None,
|
||||||
|
signed: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
value_type: None,
|
||||||
|
span: (
|
||||||
|
231,
|
||||||
|
241,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Let {
|
||||||
|
name: "z",
|
||||||
|
value: Variable {
|
||||||
|
name: Spanned {
|
||||||
|
span: (
|
||||||
|
254,
|
||||||
|
255,
|
||||||
|
),
|
||||||
|
value: "y",
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
span: (
|
||||||
|
246,
|
||||||
|
256,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Return(
|
||||||
|
Some(
|
||||||
|
Call {
|
||||||
|
function: "works",
|
||||||
|
args: [
|
||||||
|
Variable {
|
||||||
|
name: Spanned {
|
||||||
|
span: (
|
||||||
|
274,
|
||||||
|
275,
|
||||||
|
),
|
||||||
|
value: "z",
|
||||||
|
},
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
value_type: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
return_type: Some(
|
||||||
|
Integer {
|
||||||
|
bits: 64,
|
||||||
|
signed: true,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
|
@ -110,7 +110,7 @@ fn main() -> Result<()> {
|
||||||
let lexer = Lexer::new(code.as_str());
|
let lexer = Lexer::new(code.as_str());
|
||||||
let parser = grammar::ProgramParser::new();
|
let parser = grammar::ProgramParser::new();
|
||||||
let mut ast = parser.parse(lexer)?;
|
let mut ast = parser.parse(lexer)?;
|
||||||
type_analysis::type_inference(&mut ast);
|
type_analysis::type_inference2(&mut ast);
|
||||||
println!("{ast:#?}");
|
println!("{ast:#?}");
|
||||||
}
|
}
|
||||||
Commands::Compile {
|
Commands::Compile {
|
||||||
|
|
|
@ -10,14 +10,7 @@ struct Storage {
|
||||||
functions: HashMap<String, Function>,
|
functions: HashMap<String, Function>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
// this works, but need to find a way to store the found info + handle literal integer types (or not?)
|
||||||
enum TypeGuess {
|
|
||||||
/// The guess comes from a strong source: call args, return type, let binding.
|
|
||||||
Strong,
|
|
||||||
///
|
|
||||||
Weak,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn type_inference2(ast: &mut ast::Program) {
|
pub fn type_inference2(ast: &mut ast::Program) {
|
||||||
let mut storage = Storage::default();
|
let mut storage = Storage::default();
|
||||||
|
|
||||||
|
@ -42,6 +35,8 @@ pub fn type_inference2(ast: &mut ast::Program) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbg!(&storage);
|
||||||
|
|
||||||
for function in storage.functions.values() {
|
for function in storage.functions.values() {
|
||||||
let mut scope_vars: HashMap<String, Option<TypeExp>> = HashMap::new();
|
let mut scope_vars: HashMap<String, Option<TypeExp>> = HashMap::new();
|
||||||
|
|
||||||
|
@ -49,7 +44,9 @@ pub fn type_inference2(ast: &mut ast::Program) {
|
||||||
scope_vars.insert(arg.ident.clone(), Some(arg.type_exp.clone()));
|
scope_vars.insert(arg.ident.clone(), Some(arg.type_exp.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
type_inference_scope(&function.body, &scope_vars, function, &storage);
|
let (new_scope_vars, _) =
|
||||||
|
type_inference_scope(&function.body, &scope_vars, function, &storage);
|
||||||
|
dbg!(new_scope_vars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +70,7 @@ fn type_inference_scope(
|
||||||
} => {
|
} => {
|
||||||
new_vars.insert(name.clone());
|
new_vars.insert(name.clone());
|
||||||
|
|
||||||
let exp_type = type_inference_expression(value, &scope_vars, storage);
|
let exp_type = type_inference_expression(value, &mut scope_vars, storage, None);
|
||||||
|
|
||||||
if value_type.is_none() {
|
if value_type.is_none() {
|
||||||
scope_vars.insert(name.clone(), exp_type);
|
scope_vars.insert(name.clone(), exp_type);
|
||||||
|
@ -94,7 +91,7 @@ fn type_inference_scope(
|
||||||
panic!("undeclared variable");
|
panic!("undeclared variable");
|
||||||
}
|
}
|
||||||
|
|
||||||
let exp_type = type_inference_expression(value, &scope_vars, storage);
|
let exp_type = type_inference_expression(value, &mut scope_vars, storage, None);
|
||||||
let var = scope_vars.get_mut(name).unwrap();
|
let var = scope_vars.get_mut(name).unwrap();
|
||||||
|
|
||||||
if var.is_none() {
|
if var.is_none() {
|
||||||
|
@ -108,9 +105,45 @@ fn type_inference_scope(
|
||||||
body,
|
body,
|
||||||
else_body,
|
else_body,
|
||||||
} => {
|
} => {
|
||||||
let cond_type = type_inference_expression(condition, &scope_vars, storage);
|
type_inference_expression(
|
||||||
},
|
condition,
|
||||||
Statement::Return(_) => todo!(),
|
&mut scope_vars,
|
||||||
|
storage,
|
||||||
|
Some(TypeExp::Boolean),
|
||||||
|
);
|
||||||
|
|
||||||
|
let (new_scope_vars, new_vars) =
|
||||||
|
type_inference_scope(body, &scope_vars, func, storage);
|
||||||
|
|
||||||
|
for (k, v) in new_scope_vars.into_iter() {
|
||||||
|
// not a new var within the scope (shadowing), so type info is valid
|
||||||
|
if scope_vars.contains_key(&k) && !new_vars.contains(&k) {
|
||||||
|
scope_vars.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(body) = else_body {
|
||||||
|
let (new_scope_vars, new_vars) =
|
||||||
|
type_inference_scope(body, &scope_vars, func, storage);
|
||||||
|
|
||||||
|
for (k, v) in new_scope_vars.into_iter() {
|
||||||
|
// not a new var within the scope (shadowing), so type info is valid
|
||||||
|
if scope_vars.contains_key(&k) && !new_vars.contains(&k) {
|
||||||
|
scope_vars.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Return(exp) => {
|
||||||
|
if let Some(exp) = exp {
|
||||||
|
type_inference_expression(
|
||||||
|
exp,
|
||||||
|
&mut scope_vars,
|
||||||
|
storage,
|
||||||
|
func.return_type.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Statement::Function(_) => unreachable!(),
|
Statement::Function(_) => unreachable!(),
|
||||||
Statement::Struct(_) => unreachable!(),
|
Statement::Struct(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -121,8 +154,9 @@ fn type_inference_scope(
|
||||||
|
|
||||||
fn type_inference_expression(
|
fn type_inference_expression(
|
||||||
exp: &Expression,
|
exp: &Expression,
|
||||||
scope_vars: &HashMap<String, Option<TypeExp>>,
|
scope_vars: &mut HashMap<String, Option<TypeExp>>,
|
||||||
storage: &Storage,
|
storage: &Storage,
|
||||||
|
expected_type: Option<TypeExp>,
|
||||||
) -> Option<TypeExp> {
|
) -> Option<TypeExp> {
|
||||||
match exp {
|
match exp {
|
||||||
Expression::Literal(lit) => {
|
Expression::Literal(lit) => {
|
||||||
|
@ -148,24 +182,44 @@ fn type_inference_expression(
|
||||||
Expression::Variable {
|
Expression::Variable {
|
||||||
name,
|
name,
|
||||||
value_type: _,
|
value_type: _,
|
||||||
} => scope_vars.get(&name.value).cloned().flatten(),
|
} => {
|
||||||
|
let var = scope_vars.get(&name.value).cloned().flatten();
|
||||||
|
|
||||||
|
if expected_type.is_some() {
|
||||||
|
if var.is_none() {
|
||||||
|
scope_vars.insert(name.value.clone(), expected_type.clone());
|
||||||
|
expected_type
|
||||||
|
} else if expected_type.is_some() {
|
||||||
|
assert_eq!(var, expected_type, "type mismatch with variables");
|
||||||
|
expected_type
|
||||||
|
} else {
|
||||||
|
var
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var
|
||||||
|
}
|
||||||
|
}
|
||||||
Expression::Call {
|
Expression::Call {
|
||||||
function,
|
function,
|
||||||
args: _,
|
args,
|
||||||
value_type: _,
|
value_type: _,
|
||||||
} => storage
|
} => {
|
||||||
.functions
|
let func = storage.functions.get(function).cloned().unwrap();
|
||||||
.get(function)
|
|
||||||
.map(|x| &x.return_type)
|
for (i, arg) in args.iter().enumerate() {
|
||||||
.cloned()
|
let arg_type = func.params[i].type_exp.clone();
|
||||||
.flatten(),
|
// result is ignored, but need these to infer call arg types
|
||||||
|
type_inference_expression(arg, scope_vars, storage, Some(arg_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
func.return_type
|
||||||
|
}
|
||||||
Expression::BinaryOp(lhs, op, rhs) => match op {
|
Expression::BinaryOp(lhs, op, rhs) => match op {
|
||||||
ast::OpCode::Eq | ast::OpCode::Ne => {
|
ast::OpCode::Eq | ast::OpCode::Ne => Some(TypeExp::Boolean),
|
||||||
Some(TypeExp::Boolean)
|
|
||||||
},
|
|
||||||
_ => {
|
_ => {
|
||||||
let lhs_type = type_inference_expression(lhs, scope_vars, storage);
|
let lhs_type =
|
||||||
let rhs_type = type_inference_expression(rhs, scope_vars, storage);
|
type_inference_expression(lhs, scope_vars, storage, expected_type.clone());
|
||||||
|
let rhs_type = type_inference_expression(rhs, scope_vars, storage, expected_type);
|
||||||
|
|
||||||
if lhs_type.is_some() && rhs_type.is_some() {
|
if lhs_type.is_some() && rhs_type.is_some() {
|
||||||
assert_eq!(lhs_type, rhs_type, "types should match");
|
assert_eq!(lhs_type, rhs_type, "types should match");
|
||||||
|
|
Loading…
Reference in a new issue