From 4146c0b28c2d15dec0d7676331c6f2907ec6cc58 Mon Sep 17 00:00:00 2001 From: marihachi Date: Mon, 13 Feb 2023 17:16:06 +0900 Subject: [PATCH 01/16] add struct declaration --- uguisu-engine/src/ast.rs | 57 +++++++++++++++++++++++++++++++ uguisu-engine/src/hir.rs | 29 +++++++++++++++- uguisu-engine/src/hir_generate.rs | 37 ++++++++++++++++++-- uguisu-engine/src/hir_run.rs | 7 +++- uguisu-engine/src/parse.rs | 27 +++++++++++++-- 5 files changed, 151 insertions(+), 6 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index 4da96620..82082d46 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -5,6 +5,8 @@ pub enum Node { // statement FunctionDeclaration(FunctionDeclaration), VariableDeclaration(VariableDeclaration), + StructDeclaration(StructDeclaration), + StructField(StructField), BreakStatement(BreakStatement), ReturnStatement(ReturnStatement), Assignment(Assignment), @@ -27,6 +29,8 @@ impl Node { match self { Node::FunctionDeclaration(_) => "FunctionDeclaration", Node::VariableDeclaration(_) => "VariableDeclaration", + Node::StructDeclaration(_) => "StructDeclaration", + Node::StructField(_) => "StructField", Node::BreakStatement(_) => "BreakStatement", Node::ReturnStatement(_) => "ReturnStatement", Node::Assignment(_) => "Assignment", @@ -47,6 +51,8 @@ impl Node { match self { Node::FunctionDeclaration(node) => node.pos, Node::VariableDeclaration(node) => node.pos, + Node::StructDeclaration(node) => node.pos, + Node::StructField(node) => node.pos, Node::BreakStatement(node) => node.pos, Node::ReturnStatement(node) => node.pos, Node::Assignment(node) => node.pos, @@ -109,6 +115,26 @@ impl Node { }) } + pub fn new_struct_declaration( + identifier: String, + fields: Vec, + pos: usize, + ) -> Self { + Node::StructDeclaration(StructDeclaration { + identifier, + fields, + pos, + }) + } + + pub fn new_struct_field(identifier: String, type_identifier: String, pos: usize) -> Self { + Node::StructField(StructField { + identifier, + type_identifier, + pos, + }) + } + pub fn new_break_statement(pos: usize) -> Self { Node::BreakStatement(BreakStatement { pos, @@ -198,6 +224,13 @@ impl Node { } } + pub fn as_struct_field(&self) -> &StructField { + match self { + Node::StructField(x) => x, + _ => panic!("struct field expected"), + } + } + pub fn as_reference(&self) -> &Reference { match self { Node::Reference(x) => x, @@ -236,6 +269,20 @@ pub struct VariableDeclaration { pub pos: usize, } +#[derive(Debug, PartialEq)] +pub struct StructDeclaration { + pub identifier: String, + pub fields: Vec, // StructField + pub pos: usize, +} + +#[derive(Debug, PartialEq)] +pub struct StructField { + pub identifier: String, + pub type_identifier: String, + pub pos: usize, +} + #[derive(Debug, PartialEq)] pub enum VariableAttribute { Const, @@ -412,6 +459,16 @@ fn show_node(node: &Node, source_code: &str, level: usize) { } println!("{}}}", indent(level + 1)); } + Node::StructDeclaration(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}fields: {{", indent(level + 1)); + show_tree(&node.fields, source_code, level + 2); + println!("{}}}", indent(level + 1)); + } + Node::StructField(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); + } Node::BreakStatement(_) => {} Node::ReturnStatement(node) => { println!("{}body: {{", indent(level + 1)); diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index 8631c0ae..ec7bb5f8 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -1,5 +1,6 @@ -use std::{collections::BTreeMap, fmt}; use crate::ast; +use std::collections::BTreeMap; +use std::fmt; #[derive(Debug)] pub enum Node { @@ -21,6 +22,7 @@ pub enum Node { LogicalUnaryOp(LogicalUnaryOp), CallExpr(CallExpr), FuncParam(FuncParam), + StructField(StructField), } impl Node { @@ -42,6 +44,7 @@ impl Node { Node::LogicalUnaryOp(_) => "LogicalUnaryOp", Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", + Node::StructField(_) => "StructField", } } @@ -246,6 +249,7 @@ pub struct Declaration { pub enum Signature { FunctionSignature(FunctionSignature), VariableSignature(VariableSignature), + StructSignature(StructSignature), } impl Signature { @@ -269,6 +273,17 @@ pub struct VariableSignature { pub specified_ty: Option, } +#[derive(Debug)] +pub struct StructSignature { + /// StructField + pub fields: Vec, +} + +#[derive(Debug, Clone)] +pub struct StructField { + pub identifier: String, +} + #[derive(Debug)] pub struct BreakStatement { } @@ -461,6 +476,15 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb } println!(" }}"); } + Signature::StructSignature(signature) => { + println!(" signature(StructSignature): {{"); + println!(" fields: {{"); + for field in signature.fields.iter() { + println!(" [{}]", field); + } + println!(" }}"); + println!(" }}"); + } } } Node::Function(func) => { @@ -586,6 +610,9 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb println!(" identifier: \"{}\"", func_param.identifier); //println!(" type: {:?}", func_param.ty); } + Node::StructField(field) => { + println!(" identifier: \"{}\"", field.identifier); + } } println!("}}"); } diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 8341a57e..9a908bdd 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -18,6 +18,8 @@ use crate::hir::{ RelationalOperator, ResolverStack, Signature, + StructField, + StructSignature, SymbolTable, Type, VariableSignature, @@ -113,6 +115,9 @@ impl<'a> HirGenerator<'a> { Signature::FunctionSignature(_) => { return Err(self.make_low_error("type `function` is not supported", parser_node)); } + Signature::StructSignature(_) => { + return Err(self.make_low_error("struct is not supported", parser_node)); + } }; let ty = match signature.specified_ty { Some(x) => Type::assert(body_ty, x).map_err(|e| self.make_error(&e, body_id))?, @@ -326,6 +331,31 @@ impl<'a> HirGenerator<'a> { Ok(node_id) } + ast::Node::StructDeclaration(decl) => { + if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } + + let mut fields = Vec::new(); + for n in decl.fields.iter() { + let field_node = n.as_struct_field(); + let node = Node::StructField(StructField { + identifier: field_node.identifier.clone(), + }); + let node_id = self.register_node(node); + fields.push(node_id); + } + + // make signature + let signature = Signature::StructSignature(StructSignature { + fields: fields, + }); + // make node + let node = Node::new_declaration(decl.identifier.clone(), signature); + let node_id = self.register_node(node); + self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); + self.resolver.set_identifier(&decl.identifier, node_id); + + Ok(node_id) + } ast::Node::BreakStatement(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } if self.resolver.is_root_frame() { @@ -505,7 +535,8 @@ impl<'a> HirGenerator<'a> { } Ok(expr_id) } - ast::Node::FuncParam(_) => { + ast::Node::FuncParam(_) + | ast::Node::StructField(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } panic!("unexpected node"); } @@ -694,12 +725,14 @@ impl<'a> HirGenerator<'a> { } ast::Node::FunctionDeclaration(_) | ast::Node::VariableDeclaration(_) + | ast::Node::StructDeclaration(_) | ast::Node::BreakStatement(_) | ast::Node::ReturnStatement(_) | ast::Node::Assignment(_) | ast::Node::IfStatement(_) | ast::Node::LoopStatement(_) - | ast::Node::FuncParam(_) => { + | ast::Node::FuncParam(_) + | ast::Node::StructField(_) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } panic!("unexpected expr node"); } diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index 79cf21c5..8c54fb98 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -199,6 +199,9 @@ impl<'a> HirRunner<'a> { None => {} // variable is not defined yet } } + Signature::StructSignature(_) => { + todo!(); + } } Ok(StatementResult::None) } @@ -314,7 +317,8 @@ impl<'a> HirRunner<'a> { } Node::Function(_) | Node::Variable(_) - | Node::FuncParam(_) => { + | Node::FuncParam(_) + | Node::StructField(_) => { panic!("Failed to execute the statement: unsupported node (node_id={})", node_id); } }; @@ -469,6 +473,7 @@ impl<'a> HirRunner<'a> { } Node::Function(_) => panic!("function object unsupported (node_id={})", node_id), Node::FuncParam(_) + | Node::StructField(_) | Node::Declaration(_) | Node::ReturnStatement(_) | Node::BreakStatement(_) diff --git a/uguisu-engine/src/parse.rs b/uguisu-engine/src/parse.rs index 22313384..0bed78f3 100644 --- a/uguisu-engine/src/parse.rs +++ b/uguisu-engine/src/parse.rs @@ -59,6 +59,7 @@ peg::parser! { pub(crate) rule statement() -> Node = function_declaration() + / struct_declaration() / break_statement() / return_statement() / variable_declaration() @@ -101,7 +102,7 @@ peg::parser! { rule function_declaration() -> Node = p:pos() attrs:func_dec_attrs()? "fn" __+ name:idenfitier() __* "(" __* params:func_dec_params()? __* ")" - __* ret:func_dec_return_type()? __* body:func_dec_body() + __* ret:type_label()? __* body:func_dec_body() { let params = if let Some(v) = params { v } else { vec![] }; let attrs = if let Some(v) = attrs { v } else { vec![] }; @@ -115,7 +116,7 @@ peg::parser! { = p:pos() name:idenfitier() type_name:(__* ":" __* n:idenfitier() { n.to_string() })? { Node::new_func_param(name.to_string(), type_name, p) } - rule func_dec_return_type() -> String + rule type_label() -> String = ":" __* type_name:idenfitier() { type_name.to_string() } rule func_dec_body() -> Option> @@ -129,6 +130,28 @@ peg::parser! { // rule func_dec_attr() -> FunctionAttribute // = "" { } + rule struct_declaration() -> Node = + p:pos() "struct" __+ name:idenfitier() __* body:struct_body() + { + Node::new_struct_declaration(name.to_string(), body, p) + } + + rule struct_body() -> Vec = + "{" __* s:(struct_field() ++ (__*))? __* "}" + { + if let Some(nodes) = s { + nodes + } else { + vec![] + } + } + + rule struct_field() -> Node = + p:pos() name:idenfitier() __* type_name:type_label() __* ";" + { + Node::new_struct_field(name.to_string(), type_name, p) + } + rule break_statement() -> Node = p:pos() "break" __* ";" { Node::new_break_statement(p) } From 9f4ef38d2fba9656c280248022b7c45d77f4fe27 Mon Sep 17 00:00:00 2001 From: marihachi Date: Mon, 13 Feb 2023 17:25:03 +0900 Subject: [PATCH 02/16] refactor --- uguisu-engine/src/ast.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index 82082d46..4a103947 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -6,7 +6,6 @@ pub enum Node { FunctionDeclaration(FunctionDeclaration), VariableDeclaration(VariableDeclaration), StructDeclaration(StructDeclaration), - StructField(StructField), BreakStatement(BreakStatement), ReturnStatement(ReturnStatement), Assignment(Assignment), @@ -22,6 +21,8 @@ pub enum Node { CallExpr(CallExpr), // function declaration FuncParam(FuncParam), + // struct declaration + StructField(StructField), } impl Node { @@ -30,7 +31,6 @@ impl Node { Node::FunctionDeclaration(_) => "FunctionDeclaration", Node::VariableDeclaration(_) => "VariableDeclaration", Node::StructDeclaration(_) => "StructDeclaration", - Node::StructField(_) => "StructField", Node::BreakStatement(_) => "BreakStatement", Node::ReturnStatement(_) => "ReturnStatement", Node::Assignment(_) => "Assignment", @@ -44,6 +44,7 @@ impl Node { Node::UnaryOp(_) => "UnaryOp", Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", + Node::StructField(_) => "StructField", } } @@ -52,7 +53,6 @@ impl Node { Node::FunctionDeclaration(node) => node.pos, Node::VariableDeclaration(node) => node.pos, Node::StructDeclaration(node) => node.pos, - Node::StructField(node) => node.pos, Node::BreakStatement(node) => node.pos, Node::ReturnStatement(node) => node.pos, Node::Assignment(node) => node.pos, @@ -66,6 +66,7 @@ impl Node { Node::UnaryOp(node) => node.pos, Node::CallExpr(node) => node.pos, Node::FuncParam(node) => node.pos, + Node::StructField(node) => node.pos, } } @@ -465,10 +466,6 @@ fn show_node(node: &Node, source_code: &str, level: usize) { show_tree(&node.fields, source_code, level + 2); println!("{}}}", indent(level + 1)); } - Node::StructField(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); - println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); - } Node::BreakStatement(_) => {} Node::ReturnStatement(node) => { println!("{}body: {{", indent(level + 1)); @@ -575,6 +572,10 @@ fn show_node(node: &Node, source_code: &str, level: usize) { } } } + Node::StructField(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); + } } println!("{}}}", indent(level)); } From 2d1abb392e017c0a85bb246172fe9744c1da6db3 Mon Sep 17 00:00:00 2001 From: marihachi Date: Tue, 14 Feb 2023 13:58:47 +0900 Subject: [PATCH 03/16] add struct init --- uguisu-engine/src/ast.rs | 77 +++++++++++++++++++++++++++---- uguisu-engine/src/hir.rs | 46 ++++++++++++++++++ uguisu-engine/src/hir_generate.rs | 28 +++++++++-- uguisu-engine/src/hir_run.rs | 6 ++- uguisu-engine/src/parse.rs | 33 ++++++++----- 5 files changed, 165 insertions(+), 25 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index 4a103947..34655078 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -6,6 +6,7 @@ pub enum Node { FunctionDeclaration(FunctionDeclaration), VariableDeclaration(VariableDeclaration), StructDeclaration(StructDeclaration), + StructInit(StructInit), BreakStatement(BreakStatement), ReturnStatement(ReturnStatement), Assignment(Assignment), @@ -22,7 +23,9 @@ pub enum Node { // function declaration FuncParam(FuncParam), // struct declaration - StructField(StructField), + StructDeclField(StructDeclField), + // struct init + StructInitField(StructInitField), } impl Node { @@ -31,6 +34,7 @@ impl Node { Node::FunctionDeclaration(_) => "FunctionDeclaration", Node::VariableDeclaration(_) => "VariableDeclaration", Node::StructDeclaration(_) => "StructDeclaration", + Node::StructInit(_) => "StructInit", Node::BreakStatement(_) => "BreakStatement", Node::ReturnStatement(_) => "ReturnStatement", Node::Assignment(_) => "Assignment", @@ -44,7 +48,8 @@ impl Node { Node::UnaryOp(_) => "UnaryOp", Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", - Node::StructField(_) => "StructField", + Node::StructDeclField(_) => "StructDeclField", + Node::StructInitField(_) => "StructInitField", } } @@ -53,6 +58,7 @@ impl Node { Node::FunctionDeclaration(node) => node.pos, Node::VariableDeclaration(node) => node.pos, Node::StructDeclaration(node) => node.pos, + Node::StructInit(node) => node.pos, Node::BreakStatement(node) => node.pos, Node::ReturnStatement(node) => node.pos, Node::Assignment(node) => node.pos, @@ -66,7 +72,8 @@ impl Node { Node::UnaryOp(node) => node.pos, Node::CallExpr(node) => node.pos, Node::FuncParam(node) => node.pos, - Node::StructField(node) => node.pos, + Node::StructDeclField(node) => node.pos, + Node::StructInitField(node) => node.pos, } } @@ -128,14 +135,34 @@ impl Node { }) } - pub fn new_struct_field(identifier: String, type_identifier: String, pos: usize) -> Self { - Node::StructField(StructField { + pub fn new_struct_decl_field(identifier: String, type_identifier: String, pos: usize) -> Self { + Node::StructDeclField(StructDeclField { identifier, type_identifier, pos, }) } + pub fn new_struct_init( + identifier: String, + fields: Vec, + pos: usize, + ) -> Self { + Node::StructInit(StructInit { + identifier, + fields, + pos, + }) + } + + pub fn new_struct_init_field(identifier: String, body: Node, pos: usize) -> Self { + Node::StructInitField(StructInitField { + identifier, + body: Box::new(body), + pos, + }) + } + pub fn new_break_statement(pos: usize) -> Self { Node::BreakStatement(BreakStatement { pos, @@ -225,10 +252,17 @@ impl Node { } } - pub fn as_struct_field(&self) -> &StructField { + pub fn as_struct_field(&self) -> &StructDeclField { match self { - Node::StructField(x) => x, - _ => panic!("struct field expected"), + Node::StructDeclField(x) => x, + _ => panic!("struct decl field expected"), + } + } + + pub fn as_struct_init_field(&self) -> &StructInitField { + match self { + Node::StructInitField(x) => x, + _ => panic!("struct init field expected"), } } @@ -278,12 +312,26 @@ pub struct StructDeclaration { } #[derive(Debug, PartialEq)] -pub struct StructField { +pub struct StructDeclField { pub identifier: String, pub type_identifier: String, pub pos: usize, } +#[derive(Debug, PartialEq)] +pub struct StructInit { + pub identifier: String, + pub fields: Vec, // StructInitField + pub pos: usize, +} + +#[derive(Debug, PartialEq)] +pub struct StructInitField { + pub identifier: String, + pub body: Box, // expression + pub pos: usize, +} + #[derive(Debug, PartialEq)] pub enum VariableAttribute { Const, @@ -466,6 +514,12 @@ fn show_node(node: &Node, source_code: &str, level: usize) { show_tree(&node.fields, source_code, level + 2); println!("{}}}", indent(level + 1)); } + Node::StructInit(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}fields: {{", indent(level + 1)); + show_tree(&node.fields, source_code, level + 2); + println!("{}}}", indent(level + 1)); + } Node::BreakStatement(_) => {} Node::ReturnStatement(node) => { println!("{}body: {{", indent(level + 1)); @@ -572,10 +626,13 @@ fn show_node(node: &Node, source_code: &str, level: usize) { } } } - Node::StructField(node) => { + Node::StructDeclField(node) => { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); } + Node::StructInitField(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + } } println!("{}}}", indent(level)); } diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index ec7bb5f8..0e4712e0 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -22,6 +22,8 @@ pub enum Node { LogicalUnaryOp(LogicalUnaryOp), CallExpr(CallExpr), FuncParam(FuncParam), + StructInit(StructInit), + StructInitField(StructInitField), StructField(StructField), } @@ -45,6 +47,8 @@ impl Node { Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", Node::StructField(_) => "StructField", + Node::StructInit(_) => "StructInit", + Node::StructInitField(_) => "StructInitField", } } @@ -193,6 +197,23 @@ impl Node { }) } + pub fn new_struct_init( + identifier: String, + fields: Vec, + ) -> Self { + Node::StructInit(StructInit { + identifier, + fields, + }) + } + + pub fn new_struct_init_field(identifier: String, body: NodeId) -> Self { + Node::StructInitField(StructInitField { + identifier, + body, + }) + } + pub fn as_function(&self) -> Result<&Function, String> { match self { Node::Function(x) => Ok(x), @@ -437,6 +458,20 @@ pub struct CallExpr { pub args: Vec, } +#[derive(Debug, Clone)] +pub struct StructInit { + pub identifier: String, + /// StructInitField + pub fields: Vec, +} + +#[derive(Debug, Clone)] +pub struct StructInitField { + pub identifier: String, + /// expression + pub body: NodeId, +} + pub(crate) fn show_map(node_map: &BTreeMap, symbol_table: &SymbolTable) { for i in 0..node_map.len() { show_node(NodeId::new(i), node_map, symbol_table); @@ -613,6 +648,17 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb Node::StructField(field) => { println!(" identifier: \"{}\"", field.identifier); } + Node::StructInit(init) => { + println!(" identifier: \"{}\"", init.identifier); + println!(" fields: {{"); + for field in init.fields.iter() { + println!(" [{}]", field); + } + println!(" }}"); + } + Node::StructInitField(field) => { + println!(" identifier: \"{}\"", field.identifier); + } } println!("}}"); } diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 9a908bdd..be8d8254 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -522,7 +522,8 @@ impl<'a> HirGenerator<'a> { | ast::Node::StringLiteral(_) | ast::Node::BinaryExpr(_) | ast::Node::UnaryOp(_) - | ast::Node::CallExpr(_) => { + | ast::Node::CallExpr(_) + | ast::Node::StructInit(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } // when global scope if self.resolver.is_root_frame() { @@ -536,7 +537,8 @@ impl<'a> HirGenerator<'a> { Ok(expr_id) } ast::Node::FuncParam(_) - | ast::Node::StructField(_) => { + | ast::Node::StructDeclField(_) + | ast::Node::StructInitField(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } panic!("unexpected node"); } @@ -723,6 +725,25 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_ty(node_id, ret_ty); Ok(node_id) } + ast::Node::StructInit(struct_init) => { + if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } + + let mut fields = Vec::new(); + for n in struct_init.fields.iter() { + let field_node = n.as_struct_init_field(); + let field_body_id = self.generate_expr(&field_node.body)?; + let node = Node::new_struct_init_field(field_node.identifier.clone(), field_body_id); + let node_id = self.register_node(node); + fields.push(node_id); + } + + // make node + let node = Node::new_struct_init(struct_init.identifier.clone(), fields); + let node_id = self.register_node(node); + self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); + + Ok(node_id) + } ast::Node::FunctionDeclaration(_) | ast::Node::VariableDeclaration(_) | ast::Node::StructDeclaration(_) @@ -732,7 +753,8 @@ impl<'a> HirGenerator<'a> { | ast::Node::IfStatement(_) | ast::Node::LoopStatement(_) | ast::Node::FuncParam(_) - | ast::Node::StructField(_) => { + | ast::Node::StructDeclField(_) + | ast::Node::StructInitField(_) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } panic!("unexpected expr node"); } diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index 8c54fb98..f63e4f22 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -318,7 +318,9 @@ impl<'a> HirRunner<'a> { Node::Function(_) | Node::Variable(_) | Node::FuncParam(_) - | Node::StructField(_) => { + | Node::StructField(_) + | Node::StructInit(_) + | Node::StructInitField(_) => { panic!("Failed to execute the statement: unsupported node (node_id={})", node_id); } }; @@ -474,6 +476,8 @@ impl<'a> HirRunner<'a> { Node::Function(_) => panic!("function object unsupported (node_id={})", node_id), Node::FuncParam(_) | Node::StructField(_) + | Node::StructInit(_) + | Node::StructInitField(_) | Node::Declaration(_) | Node::ReturnStatement(_) | Node::BreakStatement(_) diff --git a/uguisu-engine/src/parse.rs b/uguisu-engine/src/parse.rs index 0bed78f3..6f61277d 100644 --- a/uguisu-engine/src/parse.rs +++ b/uguisu-engine/src/parse.rs @@ -96,6 +96,7 @@ peg::parser! { e:bool() { e } e:string() { e } e:call_expr() { e } + e:struct_init() { e } p:pos() id:idenfitier() { Node::new_reference(id, p) } "(" __* e:expression() __* ")" { e } } @@ -131,25 +132,35 @@ peg::parser! { // = "" { } rule struct_declaration() -> Node = - p:pos() "struct" __+ name:idenfitier() __* body:struct_body() + p:pos() "struct" __+ name:idenfitier() __* "{" __* body:(struct_decl_field() ++ (__*))? __* "}" { + let body = match body { + Some(x) => x, + None => vec![], + }; Node::new_struct_declaration(name.to_string(), body, p) } - rule struct_body() -> Vec = - "{" __* s:(struct_field() ++ (__*))? __* "}" + rule struct_decl_field() -> Node = + p:pos() name:idenfitier() __* type_name:type_label() __* ";" { - if let Some(nodes) = s { - nodes - } else { - vec![] - } + Node::new_struct_decl_field(name.to_string(), type_name, p) } - rule struct_field() -> Node = - p:pos() name:idenfitier() __* type_name:type_label() __* ";" + rule struct_init() -> Node = + p:pos() name:idenfitier() __* "{" __* body:(struct_init_field() ++ (__* "," __*))? __* ("," __*)? "}" + { + let body = match body { + Some(x) => x, + None => vec![], + }; + Node::new_struct_init(name.to_string(), body, p) + } + + rule struct_init_field() -> Node = + p:pos() name:idenfitier() __* ":" __* body:expression() { - Node::new_struct_field(name.to_string(), type_name, p) + Node::new_struct_init_field(name.to_string(), body, p) } rule break_statement() -> Node From e651e3b319ef22d4b93105a6c0f7e140e102e99e Mon Sep 17 00:00:00 2001 From: marihachi Date: Tue, 14 Feb 2023 16:13:38 +0900 Subject: [PATCH 04/16] struct --- uguisu-engine/src/builtin.rs | 36 ++++++++--------- uguisu-engine/src/hir.rs | 60 +++++++++++++++++++--------- uguisu-engine/src/hir_generate.rs | 40 +++++++++++-------- uguisu-engine/src/hir_run.rs | 65 +++++++++++++++++-------------- 4 files changed, 118 insertions(+), 83 deletions(-) diff --git a/uguisu-engine/src/builtin.rs b/uguisu-engine/src/builtin.rs index 62bf0d96..60b07364 100644 --- a/uguisu-engine/src/builtin.rs +++ b/uguisu-engine/src/builtin.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; use std::time::SystemTime; -use crate::RuntimeError; +use crate::{RuntimeError, hir}; use crate::hir::Type; use crate::hir_run::Value; @@ -24,7 +24,7 @@ impl BuiltinInfo { } } -type BuiltinHandler = fn(&Vec) -> Result; +type BuiltinHandler = fn(&Vec, &BTreeMap) -> Result; pub(crate) struct BuiltinRuntime { table: BTreeMap, @@ -41,10 +41,10 @@ impl BuiltinRuntime { self.table.insert(internal_name.to_owned(), handler); } - pub(crate) fn call(&self, identifier: &str, args: &Vec) -> Result { + pub(crate) fn call(&self, identifier: &str, args: &Vec, node_map: &BTreeMap) -> Result { match self.table.get(identifier) { Some(f) => { - f(args) + f(args, node_map) } None => panic!("unknown builtin function"), } @@ -102,29 +102,29 @@ pub(crate) fn make_infos() -> Vec { pub(crate) fn make_runtime() -> BuiltinRuntime { let mut runtime = BuiltinRuntime::new(); - fn print_str(args: &Vec) -> Result { - let value = args[0].as_string(); // value: string + fn print_str(args: &Vec, node_map: &BTreeMap) -> Result { + let value = args[0].as_string(node_map); // value: string print!("{}", value); Ok(Value::NoneValue) } runtime.add("printStr", print_str); - fn print_num(args: &Vec) -> Result { - let value = args[0].as_number(); // value: number + fn print_num(args: &Vec, node_map: &BTreeMap) -> Result { + let value = args[0].as_number(node_map); // value: number print!("{}", value); Ok(Value::NoneValue) } runtime.add("printNum", print_num); - fn print_lf(_args: &Vec) -> Result { + fn print_lf(_args: &Vec, _node_map: &BTreeMap) -> Result { print!("\n"); Ok(Value::NoneValue) } runtime.add("printLF", print_lf); - fn assert_eq(args: &Vec) -> Result { - let actual = args[0].as_number(); // actual: number - let expected = args[1].as_number(); // expected: number + fn assert_eq(args: &Vec, node_map: &BTreeMap) -> Result { + let actual = args[0].as_number(node_map); // actual: number + let expected = args[1].as_number(node_map); // expected: number if actual != expected { return Err(RuntimeError::new(format!("assertion error. expected `{}`, actual `{}`.", expected, actual).as_str())); } @@ -132,7 +132,7 @@ pub(crate) fn make_runtime() -> BuiltinRuntime { } runtime.add("assertEq", assert_eq); - fn get_unixtime(_args: &Vec) -> Result { + fn get_unixtime(_args: &Vec, _node_map: &BTreeMap) -> Result { let unixtime = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH).map_err(|_e| RuntimeError::new("getUnixtime failed"))? .as_secs(); @@ -145,17 +145,17 @@ pub(crate) fn make_runtime() -> BuiltinRuntime { } runtime.add("getUnixtime", get_unixtime); - fn concat_str(args: &Vec) -> Result { - let x = args[0].as_string(); // x: string - let y = args[1].as_string(); // y: string + fn concat_str(args: &Vec, node_map: &BTreeMap) -> Result { + let x = args[0].as_string(node_map); // x: string + let y = args[1].as_string(node_map); // y: string let mut value = x.to_string(); value += y; Ok(Value::String(value)) } runtime.add("concatStr", concat_str); - fn to_string(args: &Vec) -> Result { - let num = args[0].as_number(); // num: number + fn to_string(args: &Vec, node_map: &BTreeMap) -> Result { + let num = args[0].as_number(node_map); // num: number Ok(Value::String(num.to_string())) } runtime.add("toString", to_string); diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index 0e4712e0..80526441 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -249,7 +249,10 @@ impl NodeId { } pub fn get<'a>(&self, node_map: &'a BTreeMap) -> &'a Node { - &node_map[&self] + match node_map.get(self) { + Some(x) => x, + None => panic!("node not found"), + } } } @@ -663,29 +666,29 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb println!("}}"); } -pub(crate) struct ResolverStack { +pub struct ResolverStack { frames: Vec, trace: bool, } impl ResolverStack { - pub(crate) fn new(trace: bool) -> Self { + pub fn new(trace: bool) -> Self { Self { frames: vec![ResolverFrame::new()], trace, } } - pub(crate) fn is_root_frame(&mut self) -> bool { + pub fn is_root_frame(&mut self) -> bool { self.frames.len() == 1 } - pub(crate) fn push_frame(&mut self) { + pub fn push_frame(&mut self) { if self.trace { println!("push_frame"); } self.frames.insert(0, ResolverFrame::new()); } - pub(crate) fn pop_frame(&mut self) { + pub fn pop_frame(&mut self) { if self.trace { println!("pop_frame"); } if self.is_root_frame() { panic!("Left the root frame."); @@ -693,7 +696,7 @@ impl ResolverStack { self.frames.remove(0); } - pub(crate) fn set_identifier(&mut self, identifier: &str, node_id: NodeId) { + pub fn set_identifier(&mut self, identifier: &str, node_id: NodeId) { if self.trace { println!("set_identifier (identifier: \"{}\", node_id: [{}])", identifier, node_id); } match self.frames.get_mut(0) { Some(frame) => { @@ -703,7 +706,7 @@ impl ResolverStack { } } - pub(crate) fn lookup_identifier(&self, identifier: &str) -> Option { + pub fn lookup_identifier(&self, identifier: &str) -> Option { for frame in self.frames.iter() { match frame.table.get(identifier) { Some(&node_id) => { @@ -808,34 +811,55 @@ pub enum Type { Bool, String, Function, + Struct(NodeId), } impl Type { - pub fn get_name(&self) -> &str { + pub fn get_name(&self, node_map: &BTreeMap) -> String { match self { - Type::Void => "void", - Type::Number => "number", - Type::Bool => "bool", - Type::String => "string", - Type::Function => "function", + Type::Void => "void".to_owned(), + Type::Number => "number".to_owned(), + Type::Bool => "bool".to_owned(), + Type::String => "string".to_owned(), + Type::Function => "function".to_owned(), + Type::Struct(node_id) => { + let decl = node_id.get(node_map).as_decl().unwrap(); + let ty_name = String::from("struct ") + &decl.identifier; + ty_name + } } } - pub fn from_identifier(ty_identifier: &str) -> Result { + pub fn from_identifier(ty_identifier: &str, resolver: &ResolverStack, node_map: &BTreeMap) -> Result { match ty_identifier { "void" => Err("type `void` is invalid".to_owned()), "number" => Ok(Type::Number), "bool" => Ok(Type::Bool), "string" => Ok(Type::String), - _ => Err("unknown type name".to_owned()), + _ => { + let node_id = match resolver.lookup_identifier(ty_identifier) { + Some(x) => x, + None => return Err("unknown type name".to_owned()), + }; + let decl = match node_id.get(node_map).as_decl() { + Ok(x) => x, + Err(_) => return Err("unknown type name".to_owned()), + }; + match &decl.signature { + Signature::StructSignature(_) => { + Ok(Type::Struct(node_id)) + } + _ => return Err("unknown type name".to_owned()), + } + } } } - pub fn assert(actual: Type, expected: Type) -> Result { + pub fn assert(actual: Type, expected: Type, node_map: &BTreeMap) -> Result { if actual == expected { Ok(actual) } else { - let message = format!("type mismatched. expected `{}`, found `{}`", expected.get_name(), actual.get_name()); + let message = format!("type mismatched. expected `{}`, found `{}`", expected.get_name(node_map), actual.get_name(node_map)); Err(message) } } diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index be8d8254..d504b8f2 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -120,7 +120,7 @@ impl<'a> HirGenerator<'a> { } }; let ty = match signature.specified_ty { - Some(x) => Type::assert(body_ty, x).map_err(|e| self.make_error(&e, body_id))?, + Some(x) => Type::assert(body_ty, x, self.node_map).map_err(|e| self.make_error(&e, body_id))?, None => body_ty, }; @@ -222,7 +222,7 @@ impl<'a> HirGenerator<'a> { func_params.push(func_param); } let ret_ty = match &func.ret { - Some(x) => Type::from_identifier(x).map_err(|e| self.make_low_error(&e, parser_node))?, // TODO: improve error location + Some(x) => Type::from_identifier(x, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?, // TODO: improve error location None => Type::Void, }; @@ -235,7 +235,7 @@ impl<'a> HirGenerator<'a> { let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(&func.params[i])?); let param_type = match &func.params[i].as_func_param().type_identifier { - Some(x) => Type::from_identifier(x).map_err(|e| self.make_error(&e, node_id))?, // TODO: improve error location + Some(x) => Type::from_identifier(x, &self.resolver, self.node_map).map_err(|e| self.make_error(&e, node_id))?, // TODO: improve error location None => return Err(self.make_error("parameter type missing", node_id)), }; self.symbol_table.set_ty(node_id, param_type); @@ -311,7 +311,7 @@ impl<'a> HirGenerator<'a> { // fetch specified type // NOTE: The fact that type `void` cannot be explicitly declared is used to ensure that variables of type `void` are not declared. let specified_ty = match &variable.type_identifier { - Some(ident) => Some(Type::from_identifier(ident).map_err(|e| self.make_low_error(&e, parser_node))?), // TODO: improve error location + Some(ident) => Some(Type::from_identifier(ident, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?), // TODO: improve error location None => None, }; @@ -346,12 +346,13 @@ impl<'a> HirGenerator<'a> { // make signature let signature = Signature::StructSignature(StructSignature { - fields: fields, + fields, }); // make node let node = Node::new_declaration(decl.identifier.clone(), signature); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); + self.symbol_table.set_ty(node_id, Type::Struct(node_id)); self.resolver.set_identifier(&decl.identifier, node_id); Ok(node_id) @@ -433,7 +434,7 @@ impl<'a> HirGenerator<'a> { if expr_ty == Type::Void { return Err(self.make_error("A function call that does not return a value cannot be used as an expression.", expr_id)); } - Type::assert(expr_ty, target_ty).map_err(|e| self.make_low_error(&e, parser_node))?; + Type::assert(expr_ty, target_ty, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; } AssignmentMode::AddAssign | AssignmentMode::SubAssign @@ -441,9 +442,9 @@ impl<'a> HirGenerator<'a> { | AssignmentMode::DivAssign | AssignmentMode::ModAssign => { let target_ty = self.get_ty_or_low_err(target_id, parser_node)?; - Type::assert(target_ty, Type::Number).map_err(|e| self.make_error(&e, target_id))?; // TODO: improve error message + Type::assert(target_ty, Type::Number, self.node_map).map_err(|e| self.make_error(&e, target_id))?; // TODO: improve error message let expr_ty = self.get_ty_or_err(expr_id)?; - Type::assert(expr_ty, Type::Number).map_err(|e| self.make_error(&e, expr_id))?; + Type::assert(expr_ty, Type::Number, self.node_map).map_err(|e| self.make_error(&e, expr_id))?; } } @@ -466,7 +467,7 @@ impl<'a> HirGenerator<'a> { Some((cond, then_block)) => { let cond_id = analyzer.generate_expr(cond)?; let cond_ty = analyzer.get_ty_or_err(cond_id)?; - Type::assert(cond_ty, Type::Bool).map_err(|e| analyzer.make_error(&e, cond_id))?; + Type::assert(cond_ty, Type::Bool, analyzer.node_map).map_err(|e| analyzer.make_error(&e, cond_id))?; let then_nodes = analyzer.generate_statements(then_block)?; // next else if part let elif = transform(index + 1, analyzer, parser_node, items, else_block)?; @@ -606,7 +607,7 @@ impl<'a> HirGenerator<'a> { "!" => LogicalUnaryOperator::Not, _ => return Err(self.make_low_error("unexpected operation", parser_node)), }; - Type::assert(expr_ty, Type::Bool).map_err(|e| self.make_error(&e, expr_id))?; + Type::assert(expr_ty, Type::Bool, self.node_map).map_err(|e| self.make_error(&e, expr_id))?; let node = Node::new_logical_unary_op(op, expr_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); @@ -643,8 +644,8 @@ impl<'a> HirGenerator<'a> { _ => None, }; if let Some(op) = op { - Type::assert(left_ty, Type::Number).map_err(|e| self.make_error(&e, left_id))?; - Type::assert(right_ty, Type::Number).map_err(|e| self.make_error(&e, right_id))?; + Type::assert(left_ty, Type::Number, self.node_map).map_err(|e| self.make_error(&e, left_id))?; + Type::assert(right_ty, Type::Number, self.node_map).map_err(|e| self.make_error(&e, right_id))?; let node = Node::new_arithmetic_op(op, left_id, right_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); @@ -664,7 +665,7 @@ impl<'a> HirGenerator<'a> { _ => None, }; if let Some(op) = op { - Type::assert(right_ty, left_ty).map_err(|e| self.make_low_error(&e, parser_node))?; // TODO: improve error message + Type::assert(right_ty, left_ty, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; // TODO: improve error message let node = Node::new_relational_op(op, left_ty, left_id, right_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); @@ -680,8 +681,8 @@ impl<'a> HirGenerator<'a> { _ => None, }; if let Some(op) = op { - Type::assert(left_ty, Type::Bool).map_err(|e| self.make_error(&e, left_id))?; - Type::assert(right_ty, Type::Bool).map_err(|e| self.make_error(&e, right_id))?; + Type::assert(left_ty, Type::Bool, self.node_map).map_err(|e| self.make_error(&e, left_id))?; + Type::assert(right_ty, Type::Bool, self.node_map).map_err(|e| self.make_error(&e, right_id))?; let node = Node::new_logical_binary_op(op, left_id, right_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); @@ -716,7 +717,7 @@ impl<'a> HirGenerator<'a> { if arg_ty == Type::Void { return Err(self.make_error("A function call that does not return a value cannot be used as an expression.", arg_id)); } - Type::assert(arg_ty, param_ty).map_err(|e| self.make_error(&e, arg_id))?; + Type::assert(arg_ty, param_ty, self.node_map).map_err(|e| self.make_error(&e, arg_id))?; args.push(arg_id); } let node = Node::new_call_expr(callee_id, args); @@ -726,7 +727,11 @@ impl<'a> HirGenerator<'a> { Ok(node_id) } ast::Node::StructInit(struct_init) => { - if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } + if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } + + let ty = Type::from_identifier(&struct_init.identifier, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; + + // TODO: type check for fields let mut fields = Vec::new(); for n in struct_init.fields.iter() { @@ -741,6 +746,7 @@ impl<'a> HirGenerator<'a> { let node = Node::new_struct_init(struct_init.identifier.clone(), fields); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); + self.symbol_table.set_ty(node_id, ty); Ok(node_id) } diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index f63e4f22..7aaabf16 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -34,6 +34,7 @@ pub(crate) enum Value { Bool(bool), String(String), Function(NodeId), + Struct(NodeId), // struct init } impl Value { @@ -42,29 +43,30 @@ impl Value { Value::Number(_) => Type::Number, Value::Bool(_) => Type::Bool, Value::String(_) => Type::String, + Value::Struct(node_id) => Type::Struct(node_id.clone()), Value::Function(_) => panic!("get type error"), Value::NoneValue => panic!("get type error"), } } - pub(crate) fn as_number(&self) -> i64 { + pub(crate) fn as_number(&self, node_map: &BTreeMap) -> i64 { match self { &Value::Number(value) => value, - _ => panic!("type mismatched. expected `number`, found `{}`", self.get_type().get_name()), + _ => panic!("type mismatched. expected `number`, found `{}`", self.get_type().get_name(node_map)), } } - pub(crate) fn as_bool(&self) -> bool { + pub(crate) fn as_bool(&self, node_map: &BTreeMap) -> bool { match self { &Value::Bool(value) => value, - _ => panic!("type mismatched. expected `bool`, found `{}`", self.get_type().get_name()), + _ => panic!("type mismatched. expected `bool`, found `{}`", self.get_type().get_name(node_map)), } } - pub(crate) fn as_string(&self) -> &str { + pub(crate) fn as_string(&self, node_map: &BTreeMap) -> &str { match &self { Value::String(value) => value, - _ => panic!("type mismatched. expected `string`, found `{}`", self.get_type().get_name()), + _ => panic!("type mismatched. expected `string`, found `{}`", self.get_type().get_name(node_map)), } } } @@ -200,7 +202,7 @@ impl<'a> HirRunner<'a> { } } Signature::StructSignature(_) => { - todo!(); + env.set_symbol(node_id, Value::Struct(node_id)); } } Ok(StatementResult::None) @@ -227,8 +229,8 @@ impl<'a> HirRunner<'a> { } AssignmentMode::AddAssign => { let dest_id = self.resolve_node(statement.dest); - let restored_value = curr_value.as_number(); - let body_value = self.eval_expr(statement.body, env)?.as_number(); + let restored_value = curr_value.as_number(self.source); + let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_add(body_value) { Some(x) => x, None => return Err(RuntimeError::new("add operation overflowed")), @@ -237,8 +239,8 @@ impl<'a> HirRunner<'a> { } AssignmentMode::SubAssign => { let dest_id = self.resolve_node(statement.dest); - let restored_value = curr_value.as_number(); - let body_value = self.eval_expr(statement.body, env)?.as_number(); + let restored_value = curr_value.as_number(self.source); + let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_sub(body_value) { Some(x) => x, None => return Err(RuntimeError::new("sub operation overflowed")), @@ -247,8 +249,8 @@ impl<'a> HirRunner<'a> { } AssignmentMode::MultAssign => { let dest_id = self.resolve_node(statement.dest); - let restored_value = curr_value.as_number(); - let body_value = self.eval_expr(statement.body, env)?.as_number(); + let restored_value = curr_value.as_number(self.source); + let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_mul(body_value) { Some(x) => x, None => return Err(RuntimeError::new("mult operation overflowed")), @@ -257,8 +259,8 @@ impl<'a> HirRunner<'a> { } AssignmentMode::DivAssign => { let dest_id = self.resolve_node(statement.dest); - let restored_value = curr_value.as_number(); - let body_value = self.eval_expr(statement.body, env)?.as_number(); + let restored_value = curr_value.as_number(self.source); + let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_div(body_value) { Some(x) => x, None => return Err(RuntimeError::new("div operation overflowed")), @@ -267,8 +269,8 @@ impl<'a> HirRunner<'a> { } AssignmentMode::ModAssign => { let dest_id = self.resolve_node(statement.dest); - let restored_value = curr_value.as_number(); - let body_value = self.eval_expr(statement.body, env)?.as_number(); + let restored_value = curr_value.as_number(self.source); + let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_rem(body_value) { Some(x) => x, None => return Err(RuntimeError::new("mod operation overflowed")), @@ -279,7 +281,7 @@ impl<'a> HirRunner<'a> { Ok(StatementResult::None) } Node::IfStatement(statement) => { - let condition = self.eval_expr(statement.condition, env)?.as_bool(); + let condition = self.eval_expr(statement.condition, env)?.as_bool(self.source); let block = if condition { &statement.then_block } else { @@ -358,8 +360,8 @@ impl<'a> HirRunner<'a> { let right = self.eval_expr(expr.right, env)?; match expr.relation_type { Type::Number => { - let left = left.as_number(); - let right = right.as_number(); + let left = left.as_number(self.source); + let right = right.as_number(self.source); match expr.operator { RelationalOperator::Equal => Ok(Value::Bool(left == right)), RelationalOperator::NotEqual => Ok(Value::Bool(left != right)), @@ -370,8 +372,8 @@ impl<'a> HirRunner<'a> { } } Type::Bool => { - let left = left.as_bool(); - let right = right.as_bool(); + let left = left.as_bool(self.source); + let right = right.as_bool(self.source); match expr.operator { RelationalOperator::Equal => Ok(Value::Bool(left == right)), RelationalOperator::NotEqual => Ok(Value::Bool(left != right)), @@ -383,22 +385,23 @@ impl<'a> HirRunner<'a> { } Type::Function | Type::String - | Type::Void => { + | Type::Void + | Type::Struct(_) => { panic!("unsupported operation (node_id={})", node_id); } } } Node::LogicalBinaryOp(expr) => { - let left = self.eval_expr(expr.left, env)?.as_bool(); - let right = self.eval_expr(expr.right, env)?.as_bool(); + let left = self.eval_expr(expr.left, env)?.as_bool(self.source); + let right = self.eval_expr(expr.right, env)?.as_bool(self.source); match expr.operator { LogicalBinaryOperator::And => Ok(Value::Bool(left && right)), LogicalBinaryOperator::Or => Ok(Value::Bool(left || right)), } } Node::ArithmeticOp(expr) => { - let left = self.eval_expr(expr.left, env)?.as_number(); - let right = self.eval_expr(expr.right, env)?.as_number(); + let left = self.eval_expr(expr.left, env)?.as_number(self.source); + let right = self.eval_expr(expr.right, env)?.as_number(self.source); match expr.operator { ArithmeticOperator::Add => match left.checked_add(right) { Some(x) => Ok(Value::Number(x)), @@ -423,7 +426,7 @@ impl<'a> HirRunner<'a> { } } Node::LogicalUnaryOp(op) => { - let expr = self.eval_expr(op.expr, env)?.as_bool(); + let expr = self.eval_expr(op.expr, env)?.as_bool(self.source); match op.operator { LogicalUnaryOperator::Not => Ok(Value::Bool(!expr)), } @@ -463,7 +466,7 @@ impl<'a> HirRunner<'a> { } } FunctionBody::NativeCode => { - result = Some(self.builtins.call(&callee.identifier, &args)?); + result = Some(self.builtins.call(&callee.identifier, &args, self.source)?); } } env.pop_frame(); @@ -473,10 +476,12 @@ impl<'a> HirRunner<'a> { }; Ok(value) } + Node::StructInit(_struct_init) => { + Ok(Value::Struct(node_id)) + } Node::Function(_) => panic!("function object unsupported (node_id={})", node_id), Node::FuncParam(_) | Node::StructField(_) - | Node::StructInit(_) | Node::StructInitField(_) | Node::Declaration(_) | Node::ReturnStatement(_) From f8893fb42759fc3ed4cd4b661bf9658641e4b64c Mon Sep 17 00:00:00 2001 From: marihachi Date: Tue, 14 Feb 2023 16:46:51 +0900 Subject: [PATCH 05/16] doc --- docs/technical/engine/memo.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/technical/engine/memo.md b/docs/technical/engine/memo.md index 92811d15..8f80c697 100644 --- a/docs/technical/engine/memo.md +++ b/docs/technical/engine/memo.md @@ -64,3 +64,7 @@ HIRノードのIDをシンボルアドレスとして使う。 ### 関数コール 元の環境で実引数を評価 -> 環境を分ける(push frame) -> 仮引数に値をセット + +### 構造体 +構造体は定義してインスタンス化を行ってから使用する。 +インタプリタ実行時、構造体の各インスタンス(`Identifier { fields }`)に対して値が生成される。 From 2f6567a915b4680c1adf07df77d247b288b81d88 Mon Sep 17 00:00:00 2001 From: marihachi Date: Tue, 14 Feb 2023 17:02:15 +0900 Subject: [PATCH 06/16] refactor --- uguisu-engine/src/ast.rs | 42 +++++++++++++++---------------- uguisu-engine/src/hir.rs | 40 ++++++++++++++--------------- uguisu-engine/src/hir_generate.rs | 24 +++++++++--------- uguisu-engine/src/hir_run.rs | 14 +++++------ uguisu-engine/src/parse.rs | 12 ++++----- 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index 34655078..f3a8b767 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -6,7 +6,6 @@ pub enum Node { FunctionDeclaration(FunctionDeclaration), VariableDeclaration(VariableDeclaration), StructDeclaration(StructDeclaration), - StructInit(StructInit), BreakStatement(BreakStatement), ReturnStatement(ReturnStatement), Assignment(Assignment), @@ -20,12 +19,13 @@ pub enum Node { BinaryExpr(BinaryExpr), UnaryOp(UnaryOp), CallExpr(CallExpr), + StructExpr(StructExpr), // function declaration FuncParam(FuncParam), // struct declaration StructDeclField(StructDeclField), - // struct init - StructInitField(StructInitField), + // struct expr + StructExprField(StructExprField), } impl Node { @@ -34,7 +34,7 @@ impl Node { Node::FunctionDeclaration(_) => "FunctionDeclaration", Node::VariableDeclaration(_) => "VariableDeclaration", Node::StructDeclaration(_) => "StructDeclaration", - Node::StructInit(_) => "StructInit", + Node::StructExpr(_) => "StructExpr", Node::BreakStatement(_) => "BreakStatement", Node::ReturnStatement(_) => "ReturnStatement", Node::Assignment(_) => "Assignment", @@ -49,7 +49,7 @@ impl Node { Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", Node::StructDeclField(_) => "StructDeclField", - Node::StructInitField(_) => "StructInitField", + Node::StructExprField(_) => "StructExprField", } } @@ -58,7 +58,7 @@ impl Node { Node::FunctionDeclaration(node) => node.pos, Node::VariableDeclaration(node) => node.pos, Node::StructDeclaration(node) => node.pos, - Node::StructInit(node) => node.pos, + Node::StructExpr(node) => node.pos, Node::BreakStatement(node) => node.pos, Node::ReturnStatement(node) => node.pos, Node::Assignment(node) => node.pos, @@ -73,7 +73,7 @@ impl Node { Node::CallExpr(node) => node.pos, Node::FuncParam(node) => node.pos, Node::StructDeclField(node) => node.pos, - Node::StructInitField(node) => node.pos, + Node::StructExprField(node) => node.pos, } } @@ -143,20 +143,20 @@ impl Node { }) } - pub fn new_struct_init( + pub fn new_struct_expr( identifier: String, fields: Vec, pos: usize, ) -> Self { - Node::StructInit(StructInit { + Node::StructExpr(StructExpr { identifier, fields, pos, }) } - pub fn new_struct_init_field(identifier: String, body: Node, pos: usize) -> Self { - Node::StructInitField(StructInitField { + pub fn new_struct_expr_field(identifier: String, body: Node, pos: usize) -> Self { + Node::StructExprField(StructExprField { identifier, body: Box::new(body), pos, @@ -252,17 +252,17 @@ impl Node { } } - pub fn as_struct_field(&self) -> &StructDeclField { + pub fn as_struct_decl_field(&self) -> &StructDeclField { match self { Node::StructDeclField(x) => x, _ => panic!("struct decl field expected"), } } - pub fn as_struct_init_field(&self) -> &StructInitField { + pub fn as_struct_expr_field(&self) -> &StructExprField { match self { - Node::StructInitField(x) => x, - _ => panic!("struct init field expected"), + Node::StructExprField(x) => x, + _ => panic!("struct expr field expected"), } } @@ -307,7 +307,7 @@ pub struct VariableDeclaration { #[derive(Debug, PartialEq)] pub struct StructDeclaration { pub identifier: String, - pub fields: Vec, // StructField + pub fields: Vec, // StructDeclField pub pos: usize, } @@ -319,14 +319,14 @@ pub struct StructDeclField { } #[derive(Debug, PartialEq)] -pub struct StructInit { +pub struct StructExpr { pub identifier: String, - pub fields: Vec, // StructInitField + pub fields: Vec, // StructExprField pub pos: usize, } #[derive(Debug, PartialEq)] -pub struct StructInitField { +pub struct StructExprField { pub identifier: String, pub body: Box, // expression pub pos: usize, @@ -514,7 +514,7 @@ fn show_node(node: &Node, source_code: &str, level: usize) { show_tree(&node.fields, source_code, level + 2); println!("{}}}", indent(level + 1)); } - Node::StructInit(node) => { + Node::StructExpr(node) => { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); println!("{}fields: {{", indent(level + 1)); show_tree(&node.fields, source_code, level + 2); @@ -630,7 +630,7 @@ fn show_node(node: &Node, source_code: &str, level: usize) { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); } - Node::StructInitField(node) => { + Node::StructExprField(node) => { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); } } diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index 80526441..d99c1e05 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -22,9 +22,9 @@ pub enum Node { LogicalUnaryOp(LogicalUnaryOp), CallExpr(CallExpr), FuncParam(FuncParam), - StructInit(StructInit), - StructInitField(StructInitField), - StructField(StructField), + StructExpr(StructExpr), + StructExprField(StructExprField), + StructDeclField(StructDeclField), } impl Node { @@ -46,9 +46,9 @@ impl Node { Node::LogicalUnaryOp(_) => "LogicalUnaryOp", Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", - Node::StructField(_) => "StructField", - Node::StructInit(_) => "StructInit", - Node::StructInitField(_) => "StructInitField", + Node::StructDeclField(_) => "StructDeclField", + Node::StructExpr(_) => "StructExpr", + Node::StructExprField(_) => "StructExprField", } } @@ -197,18 +197,18 @@ impl Node { }) } - pub fn new_struct_init( + pub fn new_struct_expr( identifier: String, fields: Vec, ) -> Self { - Node::StructInit(StructInit { + Node::StructExpr(StructExpr { identifier, fields, }) } - pub fn new_struct_init_field(identifier: String, body: NodeId) -> Self { - Node::StructInitField(StructInitField { + pub fn new_struct_expr_field(identifier: String, body: NodeId) -> Self { + Node::StructExprField(StructExprField { identifier, body, }) @@ -299,12 +299,12 @@ pub struct VariableSignature { #[derive(Debug)] pub struct StructSignature { - /// StructField + /// StructDeclField pub fields: Vec, } #[derive(Debug, Clone)] -pub struct StructField { +pub struct StructDeclField { pub identifier: String, } @@ -462,14 +462,14 @@ pub struct CallExpr { } #[derive(Debug, Clone)] -pub struct StructInit { +pub struct StructExpr { pub identifier: String, - /// StructInitField + /// StructExprField pub fields: Vec, } #[derive(Debug, Clone)] -pub struct StructInitField { +pub struct StructExprField { pub identifier: String, /// expression pub body: NodeId, @@ -648,18 +648,18 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb println!(" identifier: \"{}\"", func_param.identifier); //println!(" type: {:?}", func_param.ty); } - Node::StructField(field) => { + Node::StructDeclField(field) => { println!(" identifier: \"{}\"", field.identifier); } - Node::StructInit(init) => { - println!(" identifier: \"{}\"", init.identifier); + Node::StructExpr(struct_expr) => { + println!(" identifier: \"{}\"", struct_expr.identifier); println!(" fields: {{"); - for field in init.fields.iter() { + for field in struct_expr.fields.iter() { println!(" [{}]", field); } println!(" }}"); } - Node::StructInitField(field) => { + Node::StructExprField(field) => { println!(" identifier: \"{}\"", field.identifier); } } diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index d504b8f2..3031cff2 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -18,7 +18,7 @@ use crate::hir::{ RelationalOperator, ResolverStack, Signature, - StructField, + StructDeclField, StructSignature, SymbolTable, Type, @@ -336,8 +336,8 @@ impl<'a> HirGenerator<'a> { let mut fields = Vec::new(); for n in decl.fields.iter() { - let field_node = n.as_struct_field(); - let node = Node::StructField(StructField { + let field_node = n.as_struct_decl_field(); + let node = Node::StructDeclField(StructDeclField { identifier: field_node.identifier.clone(), }); let node_id = self.register_node(node); @@ -524,7 +524,7 @@ impl<'a> HirGenerator<'a> { | ast::Node::BinaryExpr(_) | ast::Node::UnaryOp(_) | ast::Node::CallExpr(_) - | ast::Node::StructInit(_) => { + | ast::Node::StructExpr(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } // when global scope if self.resolver.is_root_frame() { @@ -539,7 +539,7 @@ impl<'a> HirGenerator<'a> { } ast::Node::FuncParam(_) | ast::Node::StructDeclField(_) - | ast::Node::StructInitField(_) => { + | ast::Node::StructExprField(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } panic!("unexpected node"); } @@ -726,24 +726,24 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_ty(node_id, ret_ty); Ok(node_id) } - ast::Node::StructInit(struct_init) => { + ast::Node::StructExpr(struct_expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } - let ty = Type::from_identifier(&struct_init.identifier, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; + let ty = Type::from_identifier(&struct_expr.identifier, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; // TODO: type check for fields let mut fields = Vec::new(); - for n in struct_init.fields.iter() { - let field_node = n.as_struct_init_field(); + for n in struct_expr.fields.iter() { + let field_node = n.as_struct_expr_field(); let field_body_id = self.generate_expr(&field_node.body)?; - let node = Node::new_struct_init_field(field_node.identifier.clone(), field_body_id); + let node = Node::new_struct_expr_field(field_node.identifier.clone(), field_body_id); let node_id = self.register_node(node); fields.push(node_id); } // make node - let node = Node::new_struct_init(struct_init.identifier.clone(), fields); + let node = Node::new_struct_expr(struct_expr.identifier.clone(), fields); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); self.symbol_table.set_ty(node_id, ty); @@ -760,7 +760,7 @@ impl<'a> HirGenerator<'a> { | ast::Node::LoopStatement(_) | ast::Node::FuncParam(_) | ast::Node::StructDeclField(_) - | ast::Node::StructInitField(_) => { + | ast::Node::StructExprField(_) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } panic!("unexpected expr node"); } diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index 7aaabf16..ac18eedb 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -34,7 +34,7 @@ pub(crate) enum Value { Bool(bool), String(String), Function(NodeId), - Struct(NodeId), // struct init + Struct(NodeId), // struct expr } impl Value { @@ -320,9 +320,9 @@ impl<'a> HirRunner<'a> { Node::Function(_) | Node::Variable(_) | Node::FuncParam(_) - | Node::StructField(_) - | Node::StructInit(_) - | Node::StructInitField(_) => { + | Node::StructDeclField(_) + | Node::StructExpr(_) + | Node::StructExprField(_) => { panic!("Failed to execute the statement: unsupported node (node_id={})", node_id); } }; @@ -476,13 +476,13 @@ impl<'a> HirRunner<'a> { }; Ok(value) } - Node::StructInit(_struct_init) => { + Node::StructExpr(_struct_expr) => { Ok(Value::Struct(node_id)) } Node::Function(_) => panic!("function object unsupported (node_id={})", node_id), Node::FuncParam(_) - | Node::StructField(_) - | Node::StructInitField(_) + | Node::StructDeclField(_) + | Node::StructExprField(_) | Node::Declaration(_) | Node::ReturnStatement(_) | Node::BreakStatement(_) diff --git a/uguisu-engine/src/parse.rs b/uguisu-engine/src/parse.rs index 6f61277d..c1a9e19d 100644 --- a/uguisu-engine/src/parse.rs +++ b/uguisu-engine/src/parse.rs @@ -96,7 +96,7 @@ peg::parser! { e:bool() { e } e:string() { e } e:call_expr() { e } - e:struct_init() { e } + e:struct_expr() { e } p:pos() id:idenfitier() { Node::new_reference(id, p) } "(" __* e:expression() __* ")" { e } } @@ -147,20 +147,20 @@ peg::parser! { Node::new_struct_decl_field(name.to_string(), type_name, p) } - rule struct_init() -> Node = - p:pos() name:idenfitier() __* "{" __* body:(struct_init_field() ++ (__* "," __*))? __* ("," __*)? "}" + rule struct_expr() -> Node = + p:pos() name:idenfitier() __* "{" __* body:(struct_expr_field() ++ (__* "," __*))? __* ("," __*)? "}" { let body = match body { Some(x) => x, None => vec![], }; - Node::new_struct_init(name.to_string(), body, p) + Node::new_struct_expr(name.to_string(), body, p) } - rule struct_init_field() -> Node = + rule struct_expr_field() -> Node = p:pos() name:idenfitier() __* ":" __* body:expression() { - Node::new_struct_init_field(name.to_string(), body, p) + Node::new_struct_expr_field(name.to_string(), body, p) } rule break_statement() -> Node From b81948b89f1734e42e920064a60535ad65a51e34 Mon Sep 17 00:00:00 2001 From: marihachi Date: Wed, 15 Feb 2023 13:14:07 +0900 Subject: [PATCH 07/16] field access --- uguisu-engine/src/ast.rs | 53 +++++++++++++++++++++++++++ uguisu-engine/src/hir_generate.rs | 5 +++ uguisu-engine/src/parse.rs | 60 +++++++++++++++++++++++++++---- 3 files changed, 111 insertions(+), 7 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index f3a8b767..ae0f519f 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -20,6 +20,7 @@ pub enum Node { UnaryOp(UnaryOp), CallExpr(CallExpr), StructExpr(StructExpr), + FieldAccess(FieldAccess), // function declaration FuncParam(FuncParam), // struct declaration @@ -48,6 +49,7 @@ impl Node { Node::UnaryOp(_) => "UnaryOp", Node::CallExpr(_) => "CallExpr", Node::FuncParam(_) => "FuncParam", + Node::FieldAccess(_) => "FieldAccess", Node::StructDeclField(_) => "StructDeclField", Node::StructExprField(_) => "StructExprField", } @@ -72,6 +74,7 @@ impl Node { Node::UnaryOp(node) => node.pos, Node::CallExpr(node) => node.pos, Node::FuncParam(node) => node.pos, + Node::FieldAccess(node) => node.pos, Node::StructDeclField(node) => node.pos, Node::StructExprField(node) => node.pos, } @@ -245,6 +248,22 @@ impl Node { }) } + pub fn new_field_access( + identifier: String, + child: Option, + pos: usize, + ) -> Self { + let child = match child { + Some(x) => Some(Box::new(x)), + None => None, + }; + Node::FieldAccess(FieldAccess { + identifier, + child, + pos, + }) + } + pub fn as_func_param(&self) -> &FuncParam { match self { Node::FuncParam(x) => x, @@ -272,6 +291,20 @@ impl Node { _ => panic!("reference expected"), } } + + pub fn as_field_access(&self) -> &FieldAccess { + match self { + Node::FieldAccess(x) => x, + _ => panic!("field access expected"), + } + } + + pub fn as_field_access_mut(&mut self) -> &mut FieldAccess { + match self { + Node::FieldAccess(x) => x, + _ => panic!("field access expected"), + } + } } #[derive(Debug, PartialEq)] @@ -427,6 +460,13 @@ pub struct CallExpr { pub pos: usize, } +#[derive(Debug, PartialEq)] +pub struct FieldAccess { + pub identifier: String, + pub child: Option>, // FieldAccess + pub pos: usize, +} + fn indent(indent: usize) -> String { let mut buf = String::new(); for _ in 0..indent*2 { @@ -626,6 +666,19 @@ fn show_node(node: &Node, source_code: &str, level: usize) { } } } + Node::FieldAccess(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + match &node.child { + Some(x) => { + println!("{}child: {{", indent(level + 1)); + show_node(x, source_code, level + 2); + println!("{}}}", indent(level + 1)); + } + None => { + println!("{}child: (None)", indent(level + 1)); + } + } + } Node::StructDeclField(node) => { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 3031cff2..e64e85b3 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -524,6 +524,7 @@ impl<'a> HirGenerator<'a> { | ast::Node::BinaryExpr(_) | ast::Node::UnaryOp(_) | ast::Node::CallExpr(_) + | ast::Node::FieldAccess(_) | ast::Node::StructExpr(_) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } // when global scope @@ -726,6 +727,10 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_ty(node_id, ret_ty); Ok(node_id) } + ast::Node::FieldAccess(_field_access) => { + if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } + todo!(); + } ast::Node::StructExpr(struct_expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } diff --git a/uguisu-engine/src/parse.rs b/uguisu-engine/src/parse.rs index c1a9e19d..dc444819 100644 --- a/uguisu-engine/src/parse.rs +++ b/uguisu-engine/src/parse.rs @@ -92,15 +92,52 @@ peg::parser! { // p:pos() "+" __* expr:(@) { Node::new_unary_op("+", expr, p) } // p:pos() "-" __* expr:(@) { Node::new_unary_op("-", expr, p) } -- - e:number() { e } - e:bool() { e } - e:string() { e } - e:call_expr() { e } - e:struct_expr() { e } - p:pos() id:idenfitier() { Node::new_reference(id, p) } - "(" __* e:expression() __* ")" { e } + expr:expr_factor() field:(__* x:field_access() { x })? { + /// build the field access chain + /// ```text + /// expr: "x", field: ["aaa", "bbb", "ccc"] + /// | + /// v + /// "ccc" { + /// "bbb" { + /// "aaa" { + /// "x" { } + /// } + /// } + /// } + /// ``` + fn build_node(i: usize, segments: &Vec<(&str, usize)>, expr: Node) -> Node { + if i >= segments.len() { + expr + } else { + match segments.get(segments.len() - i - 1) { + Some(outer_item) => { + Node::new_field_access( + outer_item.0.to_owned(), + Some(build_node(i + 1, segments, expr)), + outer_item.1, + ) + } + None => panic!(), + } + } + } + match field { + Some(x) => build_node(0, &x, expr), + None => expr, + } + } } + rule expr_factor() -> Node + = number() + / bool() + / string() + / call_expr() + / struct_expr() + / p:pos() id:idenfitier() { Node::new_reference(id, p) } + / "(" __* e:expression() __* ")" { e } + rule function_declaration() -> Node = p:pos() attrs:func_dec_attrs()? "fn" __+ name:idenfitier() __* "(" __* params:func_dec_params()? __* ")" __* ret:type_label()? __* body:func_dec_body() @@ -255,6 +292,15 @@ peg::parser! { Node::new_loop_statement(body, p) } + rule field_access() -> Vec<(&'input str, usize)> + = field_access_segment() ++ (__*) + + rule field_access_segment() -> (&'input str, usize) + = "." __* p:pos() name:idenfitier() + { + (name, p) + } + rule block() -> Vec = "{" __* s:statements()? __* "}" { if let Some(nodes) = s { From 3e32731d8db7573b477cba6d67eba39c523491c6 Mon Sep 17 00:00:00 2001 From: marihachi Date: Thu, 16 Feb 2023 02:22:50 +0900 Subject: [PATCH 08/16] field access --- uguisu-engine/src/ast.rs | 23 ++++++----------------- uguisu-engine/src/hir.rs | 24 ++++++++++++++++++++++++ uguisu-engine/src/hir_generate.rs | 10 ++++++++-- uguisu-engine/src/hir_run.rs | 6 +++++- uguisu-engine/src/parse.rs | 8 ++++---- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index ae0f519f..eda6650a 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -250,16 +250,12 @@ impl Node { pub fn new_field_access( identifier: String, - child: Option, + target: Node, pos: usize, ) -> Self { - let child = match child { - Some(x) => Some(Box::new(x)), - None => None, - }; Node::FieldAccess(FieldAccess { identifier, - child, + target: Box::new(target), pos, }) } @@ -463,7 +459,7 @@ pub struct CallExpr { #[derive(Debug, PartialEq)] pub struct FieldAccess { pub identifier: String, - pub child: Option>, // FieldAccess + pub target: Box, pub pos: usize, } @@ -668,16 +664,9 @@ fn show_node(node: &Node, source_code: &str, level: usize) { } Node::FieldAccess(node) => { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); - match &node.child { - Some(x) => { - println!("{}child: {{", indent(level + 1)); - show_node(x, source_code, level + 2); - println!("{}}}", indent(level + 1)); - } - None => { - println!("{}child: (None)", indent(level + 1)); - } - } + println!("{}target: {{", indent(level + 1)); + show_node(&node.target, source_code, level + 2); + println!("{}}}", indent(level + 1)); } Node::StructDeclField(node) => { println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index d99c1e05..b0405922 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -25,6 +25,7 @@ pub enum Node { StructExpr(StructExpr), StructExprField(StructExprField), StructDeclField(StructDeclField), + FieldAccess(FieldAccess), } impl Node { @@ -49,6 +50,7 @@ impl Node { Node::StructDeclField(_) => "StructDeclField", Node::StructExpr(_) => "StructExpr", Node::StructExprField(_) => "StructExprField", + Node::FieldAccess(_) => "FieldAccess", } } @@ -214,6 +216,13 @@ impl Node { }) } + pub fn new_field_access(identifier: String, target: NodeId) -> Self { + Node::FieldAccess(FieldAccess { + identifier, + target, + }) + } + pub fn as_function(&self) -> Result<&Function, String> { match self { Node::Function(x) => Ok(x), @@ -308,6 +317,12 @@ pub struct StructDeclField { pub identifier: String, } +#[derive(Debug, Clone)] +pub struct FieldAccess { + pub identifier: String, + pub target: NodeId, +} + #[derive(Debug)] pub struct BreakStatement { } @@ -661,6 +676,15 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb } Node::StructExprField(field) => { println!(" identifier: \"{}\"", field.identifier); + println!(" body: {{"); + println!(" [{}]", field.body); + println!(" }}"); + } + Node::FieldAccess(node) => { + println!(" identifier: \"{}\"", node.identifier); + println!(" target: {{"); + println!(" [{}]", node.target); + println!(" }}"); } } println!("}}"); diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index e64e85b3..a5f82786 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -727,9 +727,15 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_ty(node_id, ret_ty); Ok(node_id) } - ast::Node::FieldAccess(_field_access) => { + ast::Node::FieldAccess(expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } - todo!(); + // TODO: check type + let target_id = self.generate_expr(&expr.target)?; + let node = Node::new_field_access(expr.identifier.clone(), target_id); + let node_id = self.register_node(node); + self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); + self.symbol_table.set_ty(node_id, Type::Number); // TODO: dummy type + Ok(node_id) } ast::Node::StructExpr(struct_expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index ac18eedb..533a0c2b 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -313,7 +313,8 @@ impl<'a> HirRunner<'a> { | Node::LogicalBinaryOp(_) | Node::ArithmeticOp(_) | Node::LogicalUnaryOp(_) - | Node::CallExpr(_) => { + | Node::CallExpr(_) + | Node::FieldAccess(_) => { self.eval_expr(node_id, env)?; Ok(StatementResult::None) } @@ -479,6 +480,9 @@ impl<'a> HirRunner<'a> { Node::StructExpr(_struct_expr) => { Ok(Value::Struct(node_id)) } + Node::FieldAccess(_expr) => { + todo!(); // TODO: 構造体のフィールドの値を取得して返す + } Node::Function(_) => panic!("function object unsupported (node_id={})", node_id), Node::FuncParam(_) | Node::StructDeclField(_) diff --git a/uguisu-engine/src/parse.rs b/uguisu-engine/src/parse.rs index dc444819..a24fbc9d 100644 --- a/uguisu-engine/src/parse.rs +++ b/uguisu-engine/src/parse.rs @@ -111,11 +111,11 @@ peg::parser! { expr } else { match segments.get(segments.len() - i - 1) { - Some(outer_item) => { + Some(x) => { Node::new_field_access( - outer_item.0.to_owned(), - Some(build_node(i + 1, segments, expr)), - outer_item.1, + x.0.to_owned(), + build_node(i + 1, segments, expr), + x.1, ) } None => panic!(), From 00a6d7bdc05df1f0c8ca0d6759c1d12080a9506a Mon Sep 17 00:00:00 2001 From: marihachi Date: Thu, 16 Feb 2023 02:49:24 +0900 Subject: [PATCH 09/16] rename reference -> identifier --- uguisu-engine/src/ast.rs | 26 +++++++++++++------------- uguisu-engine/src/hir.rs | 16 ++++++++-------- uguisu-engine/src/hir_generate.rs | 22 +++++++++++----------- uguisu-engine/src/hir_run.rs | 8 ++++---- uguisu-engine/src/parse.rs | 6 +++--- uguisu-engine/src/parse/test.rs | 12 ++++++------ uguisu-engine/src/test.rs | 2 +- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index eda6650a..b69c9b82 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -12,7 +12,7 @@ pub enum Node { IfStatement(IfStatement), LoopStatement(LoopStatement), // expression - Reference(Reference), + Identifier(Identifier), NumberLiteral(NumberLiteral), BoolLiteral(BoolLiteral), StringLiteral(StringLiteral), @@ -41,7 +41,7 @@ impl Node { Node::Assignment(_) => "Assignment", Node::IfStatement(_) => "IfStatement", Node::LoopStatement(_) => "LoopStatement", - Node::Reference(_) => "Reference", + Node::Identifier(_) => "Identifier", Node::NumberLiteral(_) => "NumberLiteral", Node::BoolLiteral(_) => "BoolLiteral", Node::StringLiteral(_) => "StringLiteral", @@ -66,7 +66,7 @@ impl Node { Node::Assignment(node) => node.pos, Node::IfStatement(node) => node.pos, Node::LoopStatement(node) => node.pos, - Node::Reference(node) => node.pos, + Node::Identifier(node) => node.pos, Node::NumberLiteral(node) => node.pos, Node::BoolLiteral(node) => node.pos, Node::StringLiteral(node) => node.pos, @@ -204,9 +204,9 @@ impl Node { Node::LoopStatement(LoopStatement { body, pos }) } - pub fn new_reference(identifier: &str, pos: usize) -> Self { - Node::Reference(Reference { - identifier: identifier.to_string(), + pub fn new_identifier(value: &str, pos: usize) -> Self { + Node::Identifier(Identifier { + value: value.to_string(), pos, }) } @@ -281,10 +281,10 @@ impl Node { } } - pub fn as_reference(&self) -> &Reference { + pub fn as_identifier(&self) -> &Identifier { match self { - Node::Reference(x) => x, - _ => panic!("reference expected"), + Node::Identifier(x) => x, + _ => panic!("identifier expected"), } } @@ -411,8 +411,8 @@ pub struct LoopStatement { } #[derive(Debug, PartialEq)] -pub struct Reference { - pub identifier: String, +pub struct Identifier { + pub value: String, pub pos: usize, } @@ -611,8 +611,8 @@ fn show_node(node: &Node, source_code: &str, level: usize) { show_tree(&node.body, source_code, level + 2); println!("{}}}", indent(level + 1)); } - Node::Reference(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + Node::Identifier(node) => { + println!("{}identifier: \"{}\"", indent(level + 1), node.value); } Node::NumberLiteral(node) => { println!("{}value: {:?}", indent(level + 1), node.value); diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index b0405922..56852e63 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -14,7 +14,7 @@ pub enum Node { // expression Function(Function), Variable(Variable), - Reference(Reference), + Identifier(Identifier), Literal(Literal), RelationalOp(RelationalOp), LogicalBinaryOp(LogicalBinaryOp), @@ -39,7 +39,7 @@ impl Node { Node::LoopStatement(_) => "LoopStatement", Node::Function(_) => "Function", Node::Variable(_) => "Variable", - Node::Reference(_) => "Reference", + Node::Identifier(_) => "Identifier", Node::Literal(_) => "Literal", Node::RelationalOp(_) => "RelationalOp", Node::LogicalBinaryOp(_) => "LogicalBinaryOp", @@ -122,8 +122,8 @@ impl Node { }) } - pub fn new_reference(dest: NodeId) -> Self { - Node::Reference(Reference { + pub fn new_identifier(dest: NodeId) -> Self { + Node::Identifier(Identifier { dest, }) } @@ -335,7 +335,7 @@ pub struct ReturnStatement { #[derive(Debug)] pub struct Assignment { - /// Reference + /// Identifier pub dest: NodeId, /// Expression pub body: NodeId, @@ -386,7 +386,7 @@ pub struct Variable { } #[derive(Debug)] -pub struct Reference { +pub struct Identifier { /// Declaration pub dest: NodeId, } @@ -470,7 +470,7 @@ pub enum LogicalUnaryOperator { #[derive(Debug)] pub struct CallExpr { - /// Reference (expects: Reference -> Declaration -> Function) + /// Identifier (expects: Identifier -> Declaration -> Function) pub callee: NodeId, /// Expression pub args: Vec, @@ -608,7 +608,7 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb } println!(" }}"); } - Node::Reference(x) => { + Node::Identifier(x) => { println!(" dest: {{"); println!(" [{}]", x.dest); println!(" }}"); diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index a5f82786..83b0e785 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -95,7 +95,7 @@ impl<'a> HirGenerator<'a> { fn resolve_node(&self, node_id: NodeId) -> NodeId { match node_id.get(self.node_map) { - Node::Reference(reference) => self.resolve_node(reference.dest), + Node::Identifier(identifier) => self.resolve_node(identifier.dest), _ => node_id, } } @@ -164,12 +164,12 @@ impl<'a> HirGenerator<'a> { } fn add_call_main(&mut self) -> Result { - // declaration reference of main function + // make identifier of main function let dest_id = match self.resolver.lookup_identifier("main") { Some(x) => x, None => return Err(SyntaxError::new("function `main` is not found")), }; - let callee_node = Node::new_reference(dest_id); + let callee_node = Node::new_identifier(dest_id); let callee_id = self.register_node(callee_node); let dest_ty = self.get_ty_or_err(dest_id)?; self.symbol_table.set_ty(callee_id, dest_ty); @@ -401,8 +401,8 @@ impl<'a> HirGenerator<'a> { return Err(self.make_low_error("An assignment statement cannot be used in global space", parser_node)); } - let reference = statement.dest.as_reference(); - let declaration_id = match self.resolver.lookup_identifier(&reference.identifier) { + let identifier = statement.dest.as_identifier(); + let declaration_id = match self.resolver.lookup_identifier(&identifier.value) { Some(x) => x, None => return Err(self.make_low_error("unknown identifier", parser_node)), }; @@ -413,7 +413,7 @@ impl<'a> HirGenerator<'a> { } // make target node - let target_node = Node::new_reference(declaration_id); + let target_node = Node::new_identifier(declaration_id); let target_id = self.register_node(target_node); self.symbol_table.set_pos(target_id, self.calc_location(parser_node)?); let declaration_ty = self.get_ty_or_low_err(declaration_id, parser_node)?; @@ -517,7 +517,7 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); Ok(node_id) } - ast::Node::Reference(_) + ast::Node::Identifier(_) | ast::Node::NumberLiteral(_) | ast::Node::BoolLiteral(_) | ast::Node::StringLiteral(_) @@ -555,14 +555,14 @@ impl<'a> HirGenerator<'a> { /// - generate syntax errors fn generate_expr(&mut self, parser_node: &ast::Node) -> Result { let result = match parser_node { - ast::Node::Reference(reference) => { - if self.trace { println!("enter expr (node: {}, identifier: {})", parser_node.get_name(), reference.identifier); } - let dest_id = match self.resolver.lookup_identifier(&reference.identifier) { + ast::Node::Identifier(identifier) => { + if self.trace { println!("enter expr (node: {}, identifier: {})", parser_node.get_name(), identifier.value); } + let dest_id = match self.resolver.lookup_identifier(&identifier.value) { Some(x) => x, None => return Err(self.make_low_error("unknown identifier", parser_node)), }; - let node = Node::new_reference(dest_id); + let node = Node::new_identifier(dest_id); let node_id = self.register_node(node); let dest_ty = self.get_ty_or_low_err(dest_id, parser_node)?; self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index 533a0c2b..93804671 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -148,7 +148,7 @@ impl<'a> HirRunner<'a> { fn resolve_node(&self, node_id: NodeId) -> NodeId { match node_id.get(self.source) { - Node::Reference(reference) => self.resolve_node(reference.dest), + Node::Identifier(identifier) => self.resolve_node(identifier.dest), _ => node_id, } } @@ -307,7 +307,7 @@ impl<'a> HirRunner<'a> { } Ok(result) } - Node::Reference(_) + Node::Identifier(_) | Node::Literal(_) | Node::RelationalOp(_) | Node::LogicalBinaryOp(_) @@ -342,8 +342,8 @@ impl<'a> HirRunner<'a> { Node::Variable(variable) => { // variable of initial value Ok(self.eval_expr(variable.content, env)?) } - Node::Reference(reference) => { - let dest_id = self.resolve_node(reference.dest); + Node::Identifier(identifier) => { + let dest_id = self.resolve_node(identifier.dest); match env.get_symbol(dest_id) { Some(x) => Ok(x.clone()), None => panic!("symbol not found (node_id={}, dest_id={})", node_id, dest_id), diff --git a/uguisu-engine/src/parse.rs b/uguisu-engine/src/parse.rs index a24fbc9d..3ffeb696 100644 --- a/uguisu-engine/src/parse.rs +++ b/uguisu-engine/src/parse.rs @@ -135,7 +135,7 @@ peg::parser! { / string() / call_expr() / struct_expr() - / p:pos() id:idenfitier() { Node::new_reference(id, p) } + / p:pos() id:idenfitier() { Node::new_identifier(id, p) } / "(" __* e:expression() __* ")" { e } rule function_declaration() -> Node = @@ -216,7 +216,7 @@ peg::parser! { rule assignment() -> Node = p:pos() id:idenfitier() __* mode:assignment_mode() __* e:expression() ";" { - Node::new_assignment(Node::new_reference(id, p), e, mode, p) + Node::new_assignment(Node::new_identifier(id, p), e, mode, p) } rule assignment_mode() -> AssignmentMode @@ -251,7 +251,7 @@ peg::parser! { = p:pos() name:idenfitier() __* "(" __* args:call_params()? __* ")" { let args = if let Some(v) = args { v } else { vec![] }; - Node::new_call_expr(Node::new_reference(name, p), args, p) + Node::new_call_expr(Node::new_identifier(name, p), args, p) } rule call_params() -> Vec diff --git a/uguisu-engine/src/parse/test.rs b/uguisu-engine/src/parse/test.rs index 4e7a997a..effd4001 100644 --- a/uguisu-engine/src/parse/test.rs +++ b/uguisu-engine/src/parse/test.rs @@ -147,19 +147,19 @@ fn test_declare_func_with_types_4() { #[test] fn test_identifier_single_ascii() { - if let Ok(Node::Reference(Reference { identifier, pos: 0, .. })) = uguisu_parser::expression("a") { + if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("a") { assert_eq!(identifier, "a"); } else { panic!("incorrect result 1"); } - if let Ok(Node::Reference(Reference { identifier, pos: 0, .. })) = uguisu_parser::expression("z") { + if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("z") { assert_eq!(identifier, "z"); } else { panic!("incorrect result 2"); } - if let Ok(Node::Reference(Reference { identifier, pos: 0, .. })) = uguisu_parser::expression("_") { + if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("_") { assert_eq!(identifier, "_"); } else { panic!("incorrect result 3"); @@ -172,7 +172,7 @@ fn test_identifier_single_ascii() { #[test] fn test_identifier_multi_ascii() { - if let Ok(Node::Reference(Reference { identifier, pos: 0, .. })) = uguisu_parser::expression("abc") { + if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("abc") { assert_eq!(identifier, "abc"); } else { panic!("incorrect result"); @@ -185,13 +185,13 @@ fn test_identifier_multi_ascii() { #[test] fn test_identifier_multi_byte() { - if let Ok(Node::Reference(Reference { identifier, pos: 0, .. })) = uguisu_parser::expression("あ") { + if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("あ") { assert_eq!(identifier, "あ"); } else { panic!("incorrect result"); } - if let Ok(Node::Reference(Reference { identifier, pos: 0, .. })) = uguisu_parser::expression("変数1") { + if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("変数1") { assert_eq!(identifier, "変数1"); } else { panic!("incorrect result"); diff --git a/uguisu-engine/src/test.rs b/uguisu-engine/src/test.rs index 44d80654..b6ca513d 100644 --- a/uguisu-engine/src/test.rs +++ b/uguisu-engine/src/test.rs @@ -461,7 +461,7 @@ fn test_assignment_modes() { ); } -// function reference +// function identifier #[test] fn should_generate_error_with_function_name_1() { From 31c447889c5ce1164c083cfc181a36dd64326b6f Mon Sep 17 00:00:00 2001 From: marihachi Date: Thu, 16 Feb 2023 11:16:42 +0900 Subject: [PATCH 10/16] field access --- uguisu-engine/src/hir.rs | 65 ++++++++++++++++++++++--------- uguisu-engine/src/hir_generate.rs | 54 ++++++++++++++++++------- uguisu-engine/src/hir_run.rs | 20 +++++----- 3 files changed, 98 insertions(+), 41 deletions(-) diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index 56852e63..a2f32cf0 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -201,17 +201,16 @@ impl Node { pub fn new_struct_expr( identifier: String, - fields: Vec, + fields: BTreeMap, ) -> Self { Node::StructExpr(StructExpr { identifier, - fields, + field_table: fields, }) } - pub fn new_struct_expr_field(identifier: String, body: NodeId) -> Self { + pub fn new_struct_expr_field(body: NodeId) -> Self { Node::StructExprField(StructExprField { - identifier, body, }) } @@ -230,6 +229,13 @@ impl Node { } } + pub fn as_variable(&self) -> Result<&Variable, String> { + match self { + Node::Variable(x) => Ok(x), + _ => Err("variable expected".to_owned()), + } + } + pub fn as_decl(&self) -> Result<&Declaration, String> { match self { Node::Declaration(x) => Ok(x), @@ -243,6 +249,27 @@ impl Node { _ => Err("function parameter expected".to_owned()), } } + + pub fn as_struct_decl_field(&self) -> Result<&StructDeclField, String> { + match self { + Node::StructDeclField(x) => Ok(x), + _ => Err("struct declaration field expected".to_owned()), + } + } + + pub fn as_struct_expr(&self) -> Result<&StructExpr, String> { + match self { + Node::StructExpr(x) => Ok(x), + _ => Err("struct expression expected".to_owned()), + } + } + + pub fn as_struct_expr_field(&self) -> Result<&StructExprField, String> { + match self { + Node::StructExprField(x) => Ok(x), + _ => Err("struct expression field expected".to_owned()), + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -292,6 +319,13 @@ impl Signature { _ => Err("function signature expected".to_owned()), } } + + pub fn as_struct_signature(&self) -> Result<&StructSignature, String> { + match self { + Signature::StructSignature(x) => Ok(x), + _ => Err("struct signature expected".to_owned()), + } + } } #[derive(Debug)] @@ -309,12 +343,11 @@ pub struct VariableSignature { #[derive(Debug)] pub struct StructSignature { /// StructDeclField - pub fields: Vec, + pub field_table: BTreeMap, } #[derive(Debug, Clone)] pub struct StructDeclField { - pub identifier: String, } #[derive(Debug, Clone)] @@ -480,12 +513,11 @@ pub struct CallExpr { pub struct StructExpr { pub identifier: String, /// StructExprField - pub fields: Vec, + pub field_table: BTreeMap, } #[derive(Debug, Clone)] pub struct StructExprField { - pub identifier: String, /// expression pub body: NodeId, } @@ -531,9 +563,9 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb } Signature::StructSignature(signature) => { println!(" signature(StructSignature): {{"); - println!(" fields: {{"); - for field in signature.fields.iter() { - println!(" [{}]", field); + println!(" field_table: {{"); + for (name, node_id) in signature.field_table.iter() { + println!(" \"{}\": [{}]", name, node_id); } println!(" }}"); println!(" }}"); @@ -663,19 +695,16 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb println!(" identifier: \"{}\"", func_param.identifier); //println!(" type: {:?}", func_param.ty); } - Node::StructDeclField(field) => { - println!(" identifier: \"{}\"", field.identifier); - } + Node::StructDeclField(_) => {} Node::StructExpr(struct_expr) => { println!(" identifier: \"{}\"", struct_expr.identifier); - println!(" fields: {{"); - for field in struct_expr.fields.iter() { - println!(" [{}]", field); + println!(" field_table: {{"); + for (name, node_id) in struct_expr.field_table.iter() { + println!(" \"{}\": [{}]", name, node_id); } println!(" }}"); } Node::StructExprField(field) => { - println!(" identifier: \"{}\"", field.identifier); println!(" body: {{"); println!(" [{}]", field.body); println!(" }}"); diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 83b0e785..9cbf9950 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -67,6 +67,18 @@ impl<'a> HirGenerator<'a> { crate::parse::calc_location(node.get_pos(), self.source_code).map_err(|e| SyntaxError::new(&e)) } + fn get_node_pos(&self, node_id: NodeId) -> Option<(usize, usize)> { + self.symbol_table.get(node_id).pos + } + + fn get_node_ty(&self, node_id: NodeId) -> Option { + self.symbol_table.get(node_id).ty + } + + fn get_decl_body(&self, node_id: NodeId) -> Option { + self.symbol_table.get(node_id).body + } + fn make_low_error(&self, message: &str, node: &ast::Node) -> SyntaxError { let (line, column) = self.calc_location(node).unwrap(); SyntaxError::new(&format!("{} ({}:{})", message, line, column)) @@ -93,9 +105,9 @@ impl<'a> HirGenerator<'a> { } } - fn resolve_node(&self, node_id: NodeId) -> NodeId { + fn resolve_identifier(&self, node_id: NodeId) -> NodeId { match node_id.get(self.node_map) { - Node::Identifier(identifier) => self.resolve_node(identifier.dest), + Node::Identifier(identifier) => self.resolve_identifier(identifier.dest), _ => node_id, } } @@ -334,19 +346,17 @@ impl<'a> HirGenerator<'a> { ast::Node::StructDeclaration(decl) => { if self.trace { println!("enter statement (node: {})", parser_node.get_name()); } - let mut fields = Vec::new(); + let mut field_table = BTreeMap::new(); for n in decl.fields.iter() { let field_node = n.as_struct_decl_field(); - let node = Node::StructDeclField(StructDeclField { - identifier: field_node.identifier.clone(), - }); + let node = Node::StructDeclField(StructDeclField {}); let node_id = self.register_node(node); - fields.push(node_id); + field_table.insert(field_node.identifier.clone(), node_id); } // make signature let signature = Signature::StructSignature(StructSignature { - fields, + field_table, }); // make node let node = Node::new_declaration(decl.identifier.clone(), signature); @@ -696,7 +706,7 @@ impl<'a> HirGenerator<'a> { ast::Node::CallExpr(call_expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } let callee_id = self.generate_expr(&call_expr.callee)?; - let callee_func_id = self.resolve_node(callee_id); + let callee_func_id = self.resolve_identifier(callee_id); let callee_func = callee_func_id.get(self.node_map).as_decl().map_err(|e| self.make_error(&e, callee_id))?; let signature = callee_func.signature.as_function_signature().map_err(|e| self.make_error(&e, callee_id))?; let ret_ty = signature.ret_ty; @@ -729,8 +739,26 @@ impl<'a> HirGenerator<'a> { } ast::Node::FieldAccess(expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } - // TODO: check type let target_id = self.generate_expr(&expr.target)?; + let target_decl_id = self.resolve_identifier(target_id); + let decl = target_decl_id.get(self.node_map).as_decl().map_err(|e| self.make_error(&e, target_id))?; + match decl.signature { + Signature::VariableSignature(_) => { + let decl_body_id = match self.get_decl_body(target_decl_id) { + Some(x) => x, + None => { + return Err(self.make_error("variable is not defined", target_id)); + } + }; + let variable = decl_body_id.get(self.node_map).as_variable().map_err(|e| self.make_error(&e, target_id))?; + let _struct_expr = variable.content.get(self.node_map).as_struct_expr().map_err(|e| self.make_error(&e, target_id))?; + } + Signature::FunctionSignature(_) + | Signature::StructSignature(_) => { + return Err(self.make_error("unexpected signature", target_id)); + } + } + let node = Node::new_field_access(expr.identifier.clone(), target_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); @@ -744,13 +772,13 @@ impl<'a> HirGenerator<'a> { // TODO: type check for fields - let mut fields = Vec::new(); + let mut fields = BTreeMap::new(); for n in struct_expr.fields.iter() { let field_node = n.as_struct_expr_field(); let field_body_id = self.generate_expr(&field_node.body)?; - let node = Node::new_struct_expr_field(field_node.identifier.clone(), field_body_id); + let node = Node::new_struct_expr_field(field_body_id); let node_id = self.register_node(node); - fields.push(node_id); + fields.insert(field_node.identifier.clone(), node_id); } // make node diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index 93804671..b985a0c1 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -146,9 +146,9 @@ impl<'a> HirRunner<'a> { } } - fn resolve_node(&self, node_id: NodeId) -> NodeId { + fn resolve_identifier(&self, node_id: NodeId) -> NodeId { match node_id.get(self.source) { - Node::Identifier(identifier) => self.resolve_node(identifier.dest), + Node::Identifier(identifier) => self.resolve_identifier(identifier.dest), _ => node_id, } } @@ -223,12 +223,12 @@ impl<'a> HirRunner<'a> { let curr_value = self.eval_expr(statement.dest, env)?; match statement.mode { AssignmentMode::Assign => { - let dest_id = self.resolve_node(statement.dest); + let dest_id = self.resolve_identifier(statement.dest); let value = self.eval_expr(statement.body, env)?; env.set_symbol(dest_id, value); } AssignmentMode::AddAssign => { - let dest_id = self.resolve_node(statement.dest); + let dest_id = self.resolve_identifier(statement.dest); let restored_value = curr_value.as_number(self.source); let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_add(body_value) { @@ -238,7 +238,7 @@ impl<'a> HirRunner<'a> { env.set_symbol(dest_id, Value::Number(value)); } AssignmentMode::SubAssign => { - let dest_id = self.resolve_node(statement.dest); + let dest_id = self.resolve_identifier(statement.dest); let restored_value = curr_value.as_number(self.source); let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_sub(body_value) { @@ -248,7 +248,7 @@ impl<'a> HirRunner<'a> { env.set_symbol(dest_id, Value::Number(value)); } AssignmentMode::MultAssign => { - let dest_id = self.resolve_node(statement.dest); + let dest_id = self.resolve_identifier(statement.dest); let restored_value = curr_value.as_number(self.source); let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_mul(body_value) { @@ -258,7 +258,7 @@ impl<'a> HirRunner<'a> { env.set_symbol(dest_id, Value::Number(value)); } AssignmentMode::DivAssign => { - let dest_id = self.resolve_node(statement.dest); + let dest_id = self.resolve_identifier(statement.dest); let restored_value = curr_value.as_number(self.source); let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_div(body_value) { @@ -268,7 +268,7 @@ impl<'a> HirRunner<'a> { env.set_symbol(dest_id, Value::Number(value)); } AssignmentMode::ModAssign => { - let dest_id = self.resolve_node(statement.dest); + let dest_id = self.resolve_identifier(statement.dest); let restored_value = curr_value.as_number(self.source); let body_value = self.eval_expr(statement.body, env)?.as_number(self.source); let value = match restored_value.checked_rem(body_value) { @@ -343,7 +343,7 @@ impl<'a> HirRunner<'a> { Ok(self.eval_expr(variable.content, env)?) } Node::Identifier(identifier) => { - let dest_id = self.resolve_node(identifier.dest); + let dest_id = self.resolve_identifier(identifier.dest); match env.get_symbol(dest_id) { Some(x) => Ok(x.clone()), None => panic!("symbol not found (node_id={}, dest_id={})", node_id, dest_id), @@ -433,7 +433,7 @@ impl<'a> HirRunner<'a> { } } Node::CallExpr(call_expr) => { - let callee_id = self.resolve_node(call_expr.callee); + let callee_id = self.resolve_identifier(call_expr.callee); let callee = callee_id.get(self.source).as_decl().unwrap(); let signature = callee.signature.as_function_signature().unwrap(); let func = match self.symbol_table.get(callee_id).body { From 9b57de19b47ece19bb4a2ea38ab38f09b75d8435 Mon Sep 17 00:00:00 2001 From: marihachi Date: Fri, 17 Feb 2023 16:29:26 +0900 Subject: [PATCH 11/16] check types for struct --- uguisu-engine/src/hir.rs | 7 +++ uguisu-engine/src/hir_generate.rs | 74 +++++++++++++++++++------------ 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index a2f32cf0..765a985d 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -313,6 +313,13 @@ pub enum Signature { } impl Signature { + pub fn as_variable_signature(&self) -> Result<&VariableSignature, String> { + match self { + Signature::VariableSignature(x) => Ok(x), + _ => Err("variable signature expected".to_owned()), + } + } + pub fn as_function_signature(&self) -> Result<&FunctionSignature, String> { match self { Signature::FunctionSignature(x) => Ok(x), diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 9cbf9950..845d1e29 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -349,8 +349,15 @@ impl<'a> HirGenerator<'a> { let mut field_table = BTreeMap::new(); for n in decl.fields.iter() { let field_node = n.as_struct_decl_field(); + let field_ty = Type::from_identifier( + &field_node.type_identifier, + &self.resolver, + self.node_map, + ).map_err(|e| self.make_low_error(&e, parser_node))?; let node = Node::StructDeclField(StructDeclField {}); let node_id = self.register_node(node); + self.symbol_table.set_pos(node_id, self.calc_location(n)?); + self.symbol_table.set_ty(node_id, field_ty); field_table.insert(field_node.identifier.clone(), node_id); } @@ -741,52 +748,61 @@ impl<'a> HirGenerator<'a> { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } let target_id = self.generate_expr(&expr.target)?; let target_decl_id = self.resolve_identifier(target_id); - let decl = target_decl_id.get(self.node_map).as_decl().map_err(|e| self.make_error(&e, target_id))?; - match decl.signature { - Signature::VariableSignature(_) => { - let decl_body_id = match self.get_decl_body(target_decl_id) { - Some(x) => x, - None => { - return Err(self.make_error("variable is not defined", target_id)); - } - }; - let variable = decl_body_id.get(self.node_map).as_variable().map_err(|e| self.make_error(&e, target_id))?; - let _struct_expr = variable.content.get(self.node_map).as_struct_expr().map_err(|e| self.make_error(&e, target_id))?; - } - Signature::FunctionSignature(_) - | Signature::StructSignature(_) => { - return Err(self.make_error("unexpected signature", target_id)); - } - } - + // expect variable declaration + let decl = target_decl_id.get(self.node_map).as_decl().map_err(|_| self.make_error("variable declaration expected", target_id))?; + decl.signature.as_variable_signature().map_err(|_| self.make_error("variable declaration expected", target_id))?; + let decl_body_id = match self.get_decl_body(target_decl_id) { + Some(x) => x, + None => return Err(self.make_error("variable is not defined", target_id)), + }; + let variable = decl_body_id.get(self.node_map).as_variable().map_err(|e| self.make_error(&e, target_id))?; + // expect struct expr + let struct_expr = variable.content.get(self.node_map).as_struct_expr().map_err(|e| self.make_error(&e, target_id))?; + // get field + let struct_expr_field_id = match struct_expr.field_table.get(&expr.identifier) { + Some(&x) => x, + None => return Err(self.make_low_error("unknown field name", parser_node)), + }; + let field_ty = self.get_ty_or_err(struct_expr_field_id)?; + // make node let node = Node::new_field_access(expr.identifier.clone(), target_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); - self.symbol_table.set_ty(node_id, Type::Number); // TODO: dummy type + self.symbol_table.set_ty(node_id, field_ty); Ok(node_id) } ast::Node::StructExpr(struct_expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } - let ty = Type::from_identifier(&struct_expr.identifier, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; - - // TODO: type check for fields - + let struct_decl_id = match ty { + Type::Struct(x) => x, + _ => return Err(self.make_low_error("struct type expected", parser_node)), + }; let mut fields = BTreeMap::new(); for n in struct_expr.fields.iter() { - let field_node = n.as_struct_expr_field(); - let field_body_id = self.generate_expr(&field_node.body)?; - let node = Node::new_struct_expr_field(field_body_id); + let struct_decl = struct_decl_id.get(self.node_map).as_decl().map_err(|e| self.make_low_error(&e, parser_node))?; + let struct_signature = struct_decl.signature.as_struct_signature().map_err(|e| self.make_low_error(&e, parser_node))?; + let expr_field_node = n.as_struct_expr_field(); + let decl_field_id = match struct_signature.field_table.get(&expr_field_node.identifier) { + Some(&x) => x, + None => return Err(self.make_low_error("unknown field name", parser_node)), + }; + let expr_field_body_id = self.generate_expr(&expr_field_node.body)?; + let decl_field_ty = self.get_ty_or_err(decl_field_id)?; + let expr_field_body_ty = self.get_ty_or_err(expr_field_body_id)?; + Type::assert(expr_field_body_ty, decl_field_ty, self.node_map).map_err(|e| self.make_error(&e, expr_field_body_id))?; + // make field node + let node = Node::new_struct_expr_field(expr_field_body_id); let node_id = self.register_node(node); - fields.insert(field_node.identifier.clone(), node_id); + self.symbol_table.set_pos(node_id, self.calc_location(n)?); + self.symbol_table.set_ty(node_id, expr_field_body_ty); + fields.insert(expr_field_node.identifier.clone(), node_id); } - // make node let node = Node::new_struct_expr(struct_expr.identifier.clone(), fields); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); self.symbol_table.set_ty(node_id, ty); - Ok(node_id) } ast::Node::FunctionDeclaration(_) From 51d44b6f40ba34d7625a4059ba1a49a26f7ba0a5 Mon Sep 17 00:00:00 2001 From: marihachi Date: Sat, 18 Feb 2023 02:22:51 +0900 Subject: [PATCH 12/16] improve resolve nodes --- uguisu-engine/src/hir_generate.rs | 46 ++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 845d1e29..db9df0a2 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -746,23 +746,37 @@ impl<'a> HirGenerator<'a> { } ast::Node::FieldAccess(expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } + fn resolve_to_struct_expr_field(node_id: NodeId, field_ident: &str, ctx: &HirGenerator) -> Result { + match node_id.get(ctx.node_map) { + // Identifier -> Identifier dest + Node::Identifier(ident) => { + resolve_to_struct_expr_field(ident.dest, field_ident, ctx) + } + // Declaration -> Declaration body + Node::Declaration(decl) => { + decl.signature.as_variable_signature().map_err(|_| "variable declaration expected")?; + let decl_body_id = match ctx.get_decl_body(node_id) { + Some(x) => x, + None => return Err("variable is not defined".to_owned()), + }; + let variable = decl_body_id.get(ctx.node_map).as_variable()?; + let variable_body_id = variable.content; + resolve_to_struct_expr_field(variable_body_id, field_ident, ctx) + } + // StructExpr -> StructExpr field + Node::StructExpr(struct_expr) => { + // get field + let struct_expr_field_id = match struct_expr.field_table.get(field_ident) { + Some(&x) => x, + None => return Err("unknown field name".to_owned()), + }; + Ok(struct_expr_field_id) + } + _ => Err("resolve failed. unexpected node type".to_owned()), + } + } let target_id = self.generate_expr(&expr.target)?; - let target_decl_id = self.resolve_identifier(target_id); - // expect variable declaration - let decl = target_decl_id.get(self.node_map).as_decl().map_err(|_| self.make_error("variable declaration expected", target_id))?; - decl.signature.as_variable_signature().map_err(|_| self.make_error("variable declaration expected", target_id))?; - let decl_body_id = match self.get_decl_body(target_decl_id) { - Some(x) => x, - None => return Err(self.make_error("variable is not defined", target_id)), - }; - let variable = decl_body_id.get(self.node_map).as_variable().map_err(|e| self.make_error(&e, target_id))?; - // expect struct expr - let struct_expr = variable.content.get(self.node_map).as_struct_expr().map_err(|e| self.make_error(&e, target_id))?; - // get field - let struct_expr_field_id = match struct_expr.field_table.get(&expr.identifier) { - Some(&x) => x, - None => return Err(self.make_low_error("unknown field name", parser_node)), - }; + let struct_expr_field_id = resolve_to_struct_expr_field(target_id, &expr.identifier, self).map_err(|e| self.make_error(&e, target_id))?; let field_ty = self.get_ty_or_err(struct_expr_field_id)?; // make node let node = Node::new_field_access(expr.identifier.clone(), target_id); From ef5302fd6922913beac89107a738d96c4a2ed5cb Mon Sep 17 00:00:00 2001 From: marihachi Date: Sat, 18 Feb 2023 02:34:54 +0900 Subject: [PATCH 13/16] refactor --- uguisu-engine/src/hir_generate.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index db9df0a2..4afc86a7 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -748,12 +748,10 @@ impl<'a> HirGenerator<'a> { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } fn resolve_to_struct_expr_field(node_id: NodeId, field_ident: &str, ctx: &HirGenerator) -> Result { match node_id.get(ctx.node_map) { - // Identifier -> Identifier dest - Node::Identifier(ident) => { + Node::Identifier(ident) => { // Identifier -> Identifier dest resolve_to_struct_expr_field(ident.dest, field_ident, ctx) } - // Declaration -> Declaration body - Node::Declaration(decl) => { + Node::Declaration(decl) => { // Declaration -> Declaration body decl.signature.as_variable_signature().map_err(|_| "variable declaration expected")?; let decl_body_id = match ctx.get_decl_body(node_id) { Some(x) => x, @@ -763,9 +761,7 @@ impl<'a> HirGenerator<'a> { let variable_body_id = variable.content; resolve_to_struct_expr_field(variable_body_id, field_ident, ctx) } - // StructExpr -> StructExpr field - Node::StructExpr(struct_expr) => { - // get field + Node::StructExpr(struct_expr) => { // StructExpr -> StructExpr field let struct_expr_field_id = match struct_expr.field_table.get(field_ident) { Some(&x) => x, None => return Err("unknown field name".to_owned()), From 21faf9ec34b47b28b5aa4e3363a82cc1aa166d2c Mon Sep 17 00:00:00 2001 From: marihachi Date: Sat, 18 Feb 2023 03:16:45 +0900 Subject: [PATCH 14/16] add test --- uguisu-engine/src/test.rs | 85 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/uguisu-engine/src/test.rs b/uguisu-engine/src/test.rs index b6ca513d..66d713fc 100644 --- a/uguisu-engine/src/test.rs +++ b/uguisu-engine/src/test.rs @@ -638,6 +638,91 @@ fn test_string_literal() { ); } +// struct declaration + +#[test] +fn test_struct_decl() { + run_test( + " + struct Data { + value: number; + } + fn main() { } + ", + ); +} + +// struct instance + +#[test] +fn test_struct_instance() { + run_test( + " + struct Data { + value: number; + } + fn main() { + var x: Data = Data { + value: 1, + }; + } + ", + ); +} + +// struct field access + +#[test] +fn test_struct_field_access_1() { + run_test( + " + struct Data { + value: number; + } + fn main() { + var x: Data = Data { + value: 1, + }; + var y: number = x.value; + } + ", + ); +} + +#[test] +fn test_struct_field_access_2() { + run_test( + " + struct Data { + value: number; + } + fn main() { + var x: Data = Data { + value: 1, + }; + var y: Data = x; + var z: number = y.value; + } + ", + ); +} + +#[test] +fn test_struct_field_access_3() { + run_test( + " + struct Data { + value: number; + } + fn main() { + var x: number = Data { + value: 1, + }.value; + } + ", + ); +} + // other examples #[test] From 6f5f7ab21853e4599e961e31fd225574f6f61632 Mon Sep 17 00:00:00 2001 From: marihachi Date: Sat, 18 Feb 2023 03:19:58 +0900 Subject: [PATCH 15/16] refactor --- uguisu-engine/src/hir_generate.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 4afc86a7..2c264bbb 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -19,6 +19,7 @@ use crate::hir::{ ResolverStack, Signature, StructDeclField, + StructExpr, StructSignature, SymbolTable, Type, @@ -746,12 +747,14 @@ impl<'a> HirGenerator<'a> { } ast::Node::FieldAccess(expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } - fn resolve_to_struct_expr_field(node_id: NodeId, field_ident: &str, ctx: &HirGenerator) -> Result { + fn resolve_to_struct_expr<'b>(node_id: NodeId, ctx: &'b HirGenerator) -> Result<&'b StructExpr, String> { match node_id.get(ctx.node_map) { - Node::Identifier(ident) => { // Identifier -> Identifier dest - resolve_to_struct_expr_field(ident.dest, field_ident, ctx) + Node::Identifier(ident) => { + // Identifier -> Identifier dest + resolve_to_struct_expr(ident.dest, ctx) } - Node::Declaration(decl) => { // Declaration -> Declaration body + Node::Declaration(decl) => { + // Declaration -> Declaration body decl.signature.as_variable_signature().map_err(|_| "variable declaration expected")?; let decl_body_id = match ctx.get_decl_body(node_id) { Some(x) => x, @@ -759,20 +762,20 @@ impl<'a> HirGenerator<'a> { }; let variable = decl_body_id.get(ctx.node_map).as_variable()?; let variable_body_id = variable.content; - resolve_to_struct_expr_field(variable_body_id, field_ident, ctx) + resolve_to_struct_expr(variable_body_id, ctx) } - Node::StructExpr(struct_expr) => { // StructExpr -> StructExpr field - let struct_expr_field_id = match struct_expr.field_table.get(field_ident) { - Some(&x) => x, - None => return Err("unknown field name".to_owned()), - }; - Ok(struct_expr_field_id) + Node::StructExpr(struct_expr) => { + Ok(struct_expr) } _ => Err("resolve failed. unexpected node type".to_owned()), } } let target_id = self.generate_expr(&expr.target)?; - let struct_expr_field_id = resolve_to_struct_expr_field(target_id, &expr.identifier, self).map_err(|e| self.make_error(&e, target_id))?; + let struct_expr = resolve_to_struct_expr(target_id, self).map_err(|e| self.make_error(&e, target_id))?; + let struct_expr_field_id = match struct_expr.field_table.get(&expr.identifier) { + Some(&x) => x, + None => return Err(self.make_error("unknown field name", target_id)), + }; let field_ty = self.get_ty_or_err(struct_expr_field_id)?; // make node let node = Node::new_field_access(expr.identifier.clone(), target_id); From b6b45454ed00c56864a9025742f9ba50dcd693e8 Mon Sep 17 00:00:00 2001 From: marihachi Date: Sat, 18 Feb 2023 21:09:37 +0900 Subject: [PATCH 16/16] refactor --- uguisu-engine/src/ast.rs | 106 +++++++++++++++--------------- uguisu-engine/src/hir.rs | 62 ++++++++++------- uguisu-engine/src/hir_generate.rs | 68 ++++++++++--------- uguisu-engine/src/hir_run.rs | 24 ++++--- uguisu-engine/src/parse/test.rs | 24 +++---- 5 files changed, 149 insertions(+), 135 deletions(-) diff --git a/uguisu-engine/src/ast.rs b/uguisu-engine/src/ast.rs index b69c9b82..9cf3fe49 100644 --- a/uguisu-engine/src/ast.rs +++ b/uguisu-engine/src/ast.rs @@ -81,7 +81,7 @@ impl Node { } pub fn new_function_declaration( - identifier: String, + name: String, body: Option>, params: Vec, ret: Option, @@ -89,25 +89,25 @@ impl Node { pos: usize, ) -> Self { Node::FunctionDeclaration(FunctionDeclaration { - identifier, + name, body, params, - ret, + ret_type_name: ret, attributes, pos, }) } - pub fn new_func_param(identifier: String, type_identifier: Option, pos: usize) -> Self { + pub fn new_func_param(name: String, type_identifier: Option, pos: usize) -> Self { Node::FuncParam(FuncParam { - identifier, - type_identifier, + name, + type_name: type_identifier, pos, }) } pub fn new_variable_declaration( - identifier: String, + name: String, body: Option, type_identifier: Option, attributes: Vec, @@ -118,49 +118,49 @@ impl Node { None => None, }; Node::VariableDeclaration(VariableDeclaration { - identifier, + name, body, - type_identifier, + type_name: type_identifier, attributes, pos, }) } pub fn new_struct_declaration( - identifier: String, + name: String, fields: Vec, pos: usize, ) -> Self { Node::StructDeclaration(StructDeclaration { - identifier, + name, fields, pos, }) } - pub fn new_struct_decl_field(identifier: String, type_identifier: String, pos: usize) -> Self { + pub fn new_struct_decl_field(name: String, type_identifier: String, pos: usize) -> Self { Node::StructDeclField(StructDeclField { - identifier, - type_identifier, + name, + type_name: type_identifier, pos, }) } pub fn new_struct_expr( - identifier: String, + name: String, fields: Vec, pos: usize, ) -> Self { Node::StructExpr(StructExpr { - identifier, + name, fields, pos, }) } - pub fn new_struct_expr_field(identifier: String, body: Node, pos: usize) -> Self { + pub fn new_struct_expr_field(name: String, body: Node, pos: usize) -> Self { Node::StructExprField(StructExprField { - identifier, + name, body: Box::new(body), pos, }) @@ -206,7 +206,7 @@ impl Node { pub fn new_identifier(value: &str, pos: usize) -> Self { Node::Identifier(Identifier { - value: value.to_string(), + name: value.to_string(), pos, }) } @@ -249,12 +249,12 @@ impl Node { } pub fn new_field_access( - identifier: String, + name: String, target: Node, pos: usize, ) -> Self { Node::FieldAccess(FieldAccess { - identifier, + name, target: Box::new(target), pos, }) @@ -305,10 +305,10 @@ impl Node { #[derive(Debug, PartialEq)] pub struct FunctionDeclaration { - pub identifier: String, + pub name: String, pub body: Option>, pub params: Vec, - pub ret: Option, + pub ret_type_name: Option, pub attributes: Vec, pub pos: usize, } @@ -319,15 +319,15 @@ pub enum FunctionAttribute { #[derive(Debug, PartialEq)] pub struct FuncParam { - pub identifier: String, - pub type_identifier: Option, + pub name: String, + pub type_name: Option, pub pos: usize, } #[derive(Debug, PartialEq)] pub struct VariableDeclaration { - pub identifier: String, - pub type_identifier: Option, + pub name: String, + pub type_name: Option, pub attributes: Vec, pub body: Option>, pub pos: usize, @@ -335,28 +335,28 @@ pub struct VariableDeclaration { #[derive(Debug, PartialEq)] pub struct StructDeclaration { - pub identifier: String, + pub name: String, pub fields: Vec, // StructDeclField pub pos: usize, } #[derive(Debug, PartialEq)] pub struct StructDeclField { - pub identifier: String, - pub type_identifier: String, + pub name: String, + pub type_name: String, pub pos: usize, } #[derive(Debug, PartialEq)] pub struct StructExpr { - pub identifier: String, + pub name: String, pub fields: Vec, // StructExprField pub pos: usize, } #[derive(Debug, PartialEq)] pub struct StructExprField { - pub identifier: String, + pub name: String, pub body: Box, // expression pub pos: usize, } @@ -412,7 +412,7 @@ pub struct LoopStatement { #[derive(Debug, PartialEq)] pub struct Identifier { - pub value: String, + pub name: String, pub pos: usize, } @@ -458,7 +458,7 @@ pub struct CallExpr { #[derive(Debug, PartialEq)] pub struct FieldAccess { - pub identifier: String, + pub name: String, pub target: Box, pub pos: usize, } @@ -483,7 +483,7 @@ fn show_node(node: &Node, source_code: &str, level: usize) { println!("{}{} ({}:{}) {{", indent(level), name, line, column); match node { Node::FunctionDeclaration(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); println!("{}attributes: {{", indent(level + 1)); for attr in node.attributes.iter() { @@ -495,12 +495,12 @@ fn show_node(node: &Node, source_code: &str, level: usize) { show_tree(&node.params, source_code, level + 2); println!("{}}}", indent(level + 1)); - match &node.ret { + match &node.ret_type_name { Some(x) => { - println!("{}ret: \"{}\"", indent(level + 1), x); + println!("{}ret_type_name: \"{}\"", indent(level + 1), x); } None => { - println!("{}ret: (None)", indent(level + 1)); + println!("{}ret_type_name: (None)", indent(level + 1)); } } @@ -516,7 +516,7 @@ fn show_node(node: &Node, source_code: &str, level: usize) { println!("{}}}", indent(level + 1)); } Node::VariableDeclaration(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); println!("{}attributes: {{", indent(level + 1)); for attr in node.attributes.iter() { @@ -524,12 +524,12 @@ fn show_node(node: &Node, source_code: &str, level: usize) { } println!("{}}}", indent(level + 1)); - match &node.type_identifier { + match &node.type_name { Some(x) => { - println!("{}type_identifier: \"{}\"", indent(level + 1), x); + println!("{}type_name: \"{}\"", indent(level + 1), x); } None => { - println!("{}type_identifier: (None)", indent(level + 1)); + println!("{}type_name: (None)", indent(level + 1)); } } @@ -545,13 +545,13 @@ fn show_node(node: &Node, source_code: &str, level: usize) { println!("{}}}", indent(level + 1)); } Node::StructDeclaration(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); println!("{}fields: {{", indent(level + 1)); show_tree(&node.fields, source_code, level + 2); println!("{}}}", indent(level + 1)); } Node::StructExpr(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); println!("{}fields: {{", indent(level + 1)); show_tree(&node.fields, source_code, level + 2); println!("{}}}", indent(level + 1)); @@ -612,7 +612,7 @@ fn show_node(node: &Node, source_code: &str, level: usize) { println!("{}}}", indent(level + 1)); } Node::Identifier(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.value); + println!("{}name: \"{}\"", indent(level + 1), node.name); } Node::NumberLiteral(node) => { println!("{}value: {:?}", indent(level + 1), node.value); @@ -651,29 +651,29 @@ fn show_node(node: &Node, source_code: &str, level: usize) { println!("{}}}", indent(level + 1)); } Node::FuncParam(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); - match &node.type_identifier { + match &node.type_name { Some(x) => { - println!("{}type_identifier: \"{}\"", indent(level + 1), x); + println!("{}type_name: \"{}\"", indent(level + 1), x); } None => { - println!("{}type_identifier: (None)", indent(level + 1)); + println!("{}type_name: (None)", indent(level + 1)); } } } Node::FieldAccess(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); println!("{}target: {{", indent(level + 1)); show_node(&node.target, source_code, level + 2); println!("{}}}", indent(level + 1)); } Node::StructDeclField(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); - println!("{}type_identifier: \"{}\"", indent(level + 1), node.type_identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); + println!("{}type_name: \"{}\"", indent(level + 1), node.type_name); } Node::StructExprField(node) => { - println!("{}identifier: \"{}\"", indent(level + 1), node.identifier); + println!("{}name: \"{}\"", indent(level + 1), node.name); } } println!("{}}}", indent(level)); diff --git a/uguisu-engine/src/hir.rs b/uguisu-engine/src/hir.rs index 765a985d..6711751b 100644 --- a/uguisu-engine/src/hir.rs +++ b/uguisu-engine/src/hir.rs @@ -55,11 +55,11 @@ impl Node { } pub fn new_declaration( - identifier: String, + name: String, signature: Signature, ) -> Self { Node::Declaration(Declaration { - identifier, + name, signature, }) } @@ -192,19 +192,19 @@ impl Node { }) } - pub fn new_func_param(identifier: String) -> Self { + pub fn new_func_param(name: String) -> Self { Node::FuncParam(FuncParam { - identifier, + name, // param_index, }) } pub fn new_struct_expr( - identifier: String, + name: String, fields: BTreeMap, ) -> Self { Node::StructExpr(StructExpr { - identifier, + name, field_table: fields, }) } @@ -215,9 +215,9 @@ impl Node { }) } - pub fn new_field_access(identifier: String, target: NodeId) -> Self { + pub fn new_field_access(name: String, target: NodeId) -> Self { Node::FieldAccess(FieldAccess { - identifier, + name, target, }) } @@ -300,7 +300,7 @@ impl fmt::Display for NodeId { #[derive(Debug)] pub struct Declaration { - pub identifier: String, + pub name: String, pub signature: Signature, //pub ty: Option, } @@ -359,7 +359,7 @@ pub struct StructDeclField { #[derive(Debug, Clone)] pub struct FieldAccess { - pub identifier: String, + pub name: String, pub target: NodeId, } @@ -408,7 +408,7 @@ pub struct Function { #[derive(Debug, Clone)] pub struct FuncParam { - pub identifier: String, + pub name: String, // pub param_index: usize, } @@ -518,7 +518,7 @@ pub struct CallExpr { #[derive(Debug, Clone)] pub struct StructExpr { - pub identifier: String, + pub name: String, /// StructExprField pub field_table: BTreeMap, } @@ -544,7 +544,7 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb } match node { Node::Declaration(decl) => { - println!(" identifier: \"{}\"", decl.identifier); + println!(" name: \"{}\"", decl.name); match &decl.signature { Signature::FunctionSignature(signature) => { println!(" signature(FunctionSignature): {{"); @@ -699,12 +699,12 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb println!(" }}"); } Node::FuncParam(func_param) => { - println!(" identifier: \"{}\"", func_param.identifier); + println!(" name: \"{}\"", func_param.name); //println!(" type: {:?}", func_param.ty); } Node::StructDeclField(_) => {} Node::StructExpr(struct_expr) => { - println!(" identifier: \"{}\"", struct_expr.identifier); + println!(" name: \"{}\"", struct_expr.name); println!(" field_table: {{"); for (name, node_id) in struct_expr.field_table.iter() { println!(" \"{}\": [{}]", name, node_id); @@ -717,7 +717,7 @@ pub(crate) fn show_node(node_id: NodeId, node_map: &BTreeMap, symb println!(" }}"); } Node::FieldAccess(node) => { - println!(" identifier: \"{}\"", node.identifier); + println!(" name: \"{}\"", node.name); println!(" target: {{"); println!(" [{}]", node.target); println!(" }}"); @@ -815,7 +815,8 @@ impl SymbolTable { let record = SymbolRecord { ty: None, pos: None, - body: None, + decl_body: None, + ident_body: None, }; self.table.insert(node_id, record); } @@ -838,13 +839,22 @@ impl SymbolTable { record.pos = Some(pos); } - pub fn set_body(&mut self, node_id: NodeId, body: NodeId) { - if self.trace { println!("set_body (node_id: [{}], body: [{}])", node_id, body); } + pub fn set_decl_body(&mut self, node_id: NodeId, body: NodeId) { + if self.trace { println!("set_decl_body (node_id: [{}], body: [{}])", node_id, body); } let record = match self.table.get_mut(&node_id) { Some(x) => x, None => panic!("symbol not found"), }; - record.body = Some(body); + record.decl_body = Some(body); + } + + pub fn set_ident_body(&mut self, node_id: NodeId, body: NodeId) { + if self.trace { println!("set_ident_body (node_id: [{}], body: [{}])", node_id, body); } + let record = match self.table.get_mut(&node_id) { + Some(x) => x, + None => panic!("symbol not found"), + }; + record.ident_body = Some(body); } pub fn get(&self, node_id: NodeId) -> &SymbolRecord { @@ -861,7 +871,9 @@ pub struct SymbolRecord { pub ty: Option, pub pos: Option<(usize, usize)>, /// (for Declaration) Variable or Function - pub body: Option, + pub decl_body: Option, + /// (for Identifier) + pub ident_body: Option, } #[derive(Debug, PartialEq, Clone, Copy)] @@ -884,20 +896,20 @@ impl Type { Type::Function => "function".to_owned(), Type::Struct(node_id) => { let decl = node_id.get(node_map).as_decl().unwrap(); - let ty_name = String::from("struct ") + &decl.identifier; + let ty_name = String::from("struct ") + &decl.name; ty_name } } } - pub fn from_identifier(ty_identifier: &str, resolver: &ResolverStack, node_map: &BTreeMap) -> Result { - match ty_identifier { + pub fn from_name(ty_name: &str, resolver: &ResolverStack, node_map: &BTreeMap) -> Result { + match ty_name { "void" => Err("type `void` is invalid".to_owned()), "number" => Ok(Type::Number), "bool" => Ok(Type::Bool), "string" => Ok(Type::String), _ => { - let node_id = match resolver.lookup_identifier(ty_identifier) { + let node_id = match resolver.lookup_identifier(ty_name) { Some(x) => x, None => return Err("unknown type name".to_owned()), }; diff --git a/uguisu-engine/src/hir_generate.rs b/uguisu-engine/src/hir_generate.rs index 2c264bbb..8d0a8a19 100644 --- a/uguisu-engine/src/hir_generate.rs +++ b/uguisu-engine/src/hir_generate.rs @@ -77,7 +77,11 @@ impl<'a> HirGenerator<'a> { } fn get_decl_body(&self, node_id: NodeId) -> Option { - self.symbol_table.get(node_id).body + self.symbol_table.get(node_id).decl_body + } + + fn get_ident_body(&self, node_id: NodeId) -> Option { + self.symbol_table.get(node_id).ident_body } fn make_low_error(&self, message: &str, node: &ast::Node) -> SyntaxError { @@ -143,7 +147,7 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_ty(variable_id, ty); // link declaration - self.symbol_table.set_body(decl_node_id, variable_id); + self.symbol_table.set_decl_body(decl_node_id, variable_id); self.symbol_table.set_ty(decl_node_id, ty); Ok(()) } @@ -171,7 +175,7 @@ impl<'a> HirGenerator<'a> { let decl_node = Node::new_declaration(info.name.clone(), func_signature); let node_id = self.register_node(decl_node); self.symbol_table.set_ty(node_id, Type::Function); - self.symbol_table.set_body(node_id, func_node_id); + self.symbol_table.set_decl_body(node_id, func_node_id); self.resolver.set_identifier(&info.name, node_id); node_id } @@ -229,13 +233,13 @@ impl<'a> HirGenerator<'a> { for n in func.params.iter() { let param = n.as_func_param(); let func_param = FuncParam { - identifier: param.identifier.clone(), + name: param.name.clone(), // param_index: i, }; func_params.push(func_param); } - let ret_ty = match &func.ret { - Some(x) => Type::from_identifier(x, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?, // TODO: improve error location + let ret_ty = match &func.ret_type_name { + Some(x) => Type::from_name(x, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?, // TODO: improve error location None => Type::Void, }; @@ -247,8 +251,8 @@ impl<'a> HirGenerator<'a> { let node = Node::FuncParam(func_param.clone()); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(&func.params[i])?); - let param_type = match &func.params[i].as_func_param().type_identifier { - Some(x) => Type::from_identifier(x, &self.resolver, self.node_map).map_err(|e| self.make_error(&e, node_id))?, // TODO: improve error location + let param_type = match &func.params[i].as_func_param().type_name { + Some(x) => Type::from_name(x, &self.resolver, self.node_map).map_err(|e| self.make_error(&e, node_id))?, // TODO: improve error location None => return Err(self.make_error("parameter type missing", node_id)), }; self.symbol_table.set_ty(node_id, param_type); @@ -259,11 +263,11 @@ impl<'a> HirGenerator<'a> { params, ret_ty, }); - let node = Node::new_declaration(func.identifier.clone(), signature); + let node = Node::new_declaration(func.name.clone(), signature); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); self.symbol_table.set_ty(node_id, Type::Function); - self.resolver.set_identifier(&func.identifier, node_id); + self.resolver.set_identifier(&func.name, node_id); node_id }; @@ -289,7 +293,7 @@ impl<'a> HirGenerator<'a> { None => break, }; let param = param_id.get(self.node_map).as_func_param().unwrap(); - self.resolver.set_identifier(¶m.identifier, param_id); + self.resolver.set_identifier(¶m.name, param_id); i += 1; } let func_body = match &func.body { @@ -304,13 +308,13 @@ impl<'a> HirGenerator<'a> { self.symbol_table.set_pos(func_node_id, self.calc_location(parser_node)?); // link declaration - self.symbol_table.set_body(decl_node_id, func_node_id); + self.symbol_table.set_decl_body(decl_node_id, func_node_id); } Ok(decl_node_id) } ast::Node::VariableDeclaration(variable) => { - if self.trace { println!("enter statement (node: {}, identifier: {})", parser_node.get_name(), variable.identifier); } + if self.trace { println!("enter statement (node: {}, name: {})", parser_node.get_name(), variable.name); } let has_const_attr = variable.attributes.iter().any(|x| *x == VariableAttribute::Const); if has_const_attr { @@ -323,8 +327,8 @@ impl<'a> HirGenerator<'a> { // fetch specified type // NOTE: The fact that type `void` cannot be explicitly declared is used to ensure that variables of type `void` are not declared. - let specified_ty = match &variable.type_identifier { - Some(ident) => Some(Type::from_identifier(ident, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?), // TODO: improve error location + let specified_ty = match &variable.type_name { + Some(ident) => Some(Type::from_name(ident, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?), // TODO: improve error location None => None, }; @@ -333,10 +337,10 @@ impl<'a> HirGenerator<'a> { specified_ty, }); // make node - let node = Node::new_declaration(variable.identifier.clone(), signature); + let node = Node::new_declaration(variable.name.clone(), signature); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); - self.resolver.set_identifier(&variable.identifier, node_id); + self.resolver.set_identifier(&variable.name, node_id); if let Some(var_body) = &variable.body { self.define_variable_decl(parser_node, var_body, node_id)?; @@ -350,8 +354,8 @@ impl<'a> HirGenerator<'a> { let mut field_table = BTreeMap::new(); for n in decl.fields.iter() { let field_node = n.as_struct_decl_field(); - let field_ty = Type::from_identifier( - &field_node.type_identifier, + let field_ty = Type::from_name( + &field_node.type_name, &self.resolver, self.node_map, ).map_err(|e| self.make_low_error(&e, parser_node))?; @@ -359,7 +363,7 @@ impl<'a> HirGenerator<'a> { let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(n)?); self.symbol_table.set_ty(node_id, field_ty); - field_table.insert(field_node.identifier.clone(), node_id); + field_table.insert(field_node.name.clone(), node_id); } // make signature @@ -367,11 +371,11 @@ impl<'a> HirGenerator<'a> { field_table, }); // make node - let node = Node::new_declaration(decl.identifier.clone(), signature); + let node = Node::new_declaration(decl.name.clone(), signature); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); self.symbol_table.set_ty(node_id, Type::Struct(node_id)); - self.resolver.set_identifier(&decl.identifier, node_id); + self.resolver.set_identifier(&decl.name, node_id); Ok(node_id) } @@ -420,13 +424,13 @@ impl<'a> HirGenerator<'a> { } let identifier = statement.dest.as_identifier(); - let declaration_id = match self.resolver.lookup_identifier(&identifier.value) { + let declaration_id = match self.resolver.lookup_identifier(&identifier.name) { Some(x) => x, None => return Err(self.make_low_error("unknown identifier", parser_node)), }; // if the declaration is not defined, define it. - if let None = self.symbol_table.get(declaration_id).body { + if let None = self.symbol_table.get(declaration_id).decl_body { self.define_variable_decl(parser_node, &statement.body, declaration_id)?; } @@ -574,8 +578,8 @@ impl<'a> HirGenerator<'a> { fn generate_expr(&mut self, parser_node: &ast::Node) -> Result { let result = match parser_node { ast::Node::Identifier(identifier) => { - if self.trace { println!("enter expr (node: {}, identifier: {})", parser_node.get_name(), identifier.value); } - let dest_id = match self.resolver.lookup_identifier(&identifier.value) { + if self.trace { println!("enter expr (node: {}, name: {})", parser_node.get_name(), identifier.name); } + let dest_id = match self.resolver.lookup_identifier(&identifier.name) { Some(x) => x, None => return Err(self.make_low_error("unknown identifier", parser_node)), }; @@ -772,13 +776,13 @@ impl<'a> HirGenerator<'a> { } let target_id = self.generate_expr(&expr.target)?; let struct_expr = resolve_to_struct_expr(target_id, self).map_err(|e| self.make_error(&e, target_id))?; - let struct_expr_field_id = match struct_expr.field_table.get(&expr.identifier) { + let struct_expr_field_id = match struct_expr.field_table.get(&expr.name) { Some(&x) => x, None => return Err(self.make_error("unknown field name", target_id)), }; let field_ty = self.get_ty_or_err(struct_expr_field_id)?; // make node - let node = Node::new_field_access(expr.identifier.clone(), target_id); + let node = Node::new_field_access(expr.name.clone(), target_id); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); self.symbol_table.set_ty(node_id, field_ty); @@ -786,7 +790,7 @@ impl<'a> HirGenerator<'a> { } ast::Node::StructExpr(struct_expr) => { if self.trace { println!("enter expr (node: {})", parser_node.get_name()); } - let ty = Type::from_identifier(&struct_expr.identifier, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; + let ty = Type::from_name(&struct_expr.name, &self.resolver, self.node_map).map_err(|e| self.make_low_error(&e, parser_node))?; let struct_decl_id = match ty { Type::Struct(x) => x, _ => return Err(self.make_low_error("struct type expected", parser_node)), @@ -796,7 +800,7 @@ impl<'a> HirGenerator<'a> { let struct_decl = struct_decl_id.get(self.node_map).as_decl().map_err(|e| self.make_low_error(&e, parser_node))?; let struct_signature = struct_decl.signature.as_struct_signature().map_err(|e| self.make_low_error(&e, parser_node))?; let expr_field_node = n.as_struct_expr_field(); - let decl_field_id = match struct_signature.field_table.get(&expr_field_node.identifier) { + let decl_field_id = match struct_signature.field_table.get(&expr_field_node.name) { Some(&x) => x, None => return Err(self.make_low_error("unknown field name", parser_node)), }; @@ -809,10 +813,10 @@ impl<'a> HirGenerator<'a> { let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(n)?); self.symbol_table.set_ty(node_id, expr_field_body_ty); - fields.insert(expr_field_node.identifier.clone(), node_id); + fields.insert(expr_field_node.name.clone(), node_id); } // make node - let node = Node::new_struct_expr(struct_expr.identifier.clone(), fields); + let node = Node::new_struct_expr(struct_expr.name.clone(), fields); let node_id = self.register_node(node); self.symbol_table.set_pos(node_id, self.calc_location(parser_node)?); self.symbol_table.set_ty(node_id, ty); diff --git a/uguisu-engine/src/hir_run.rs b/uguisu-engine/src/hir_run.rs index b985a0c1..7bbc60b0 100644 --- a/uguisu-engine/src/hir_run.rs +++ b/uguisu-engine/src/hir_run.rs @@ -34,7 +34,7 @@ pub(crate) enum Value { Bool(bool), String(String), Function(NodeId), - Struct(NodeId), // struct expr + Struct((NodeId, BTreeMap)), } impl Value { @@ -43,7 +43,7 @@ impl Value { Value::Number(_) => Type::Number, Value::Bool(_) => Type::Bool, Value::String(_) => Type::String, - Value::Struct(node_id) => Type::Struct(node_id.clone()), + Value::Struct((node_id, _)) => Type::Struct(node_id.clone()), Value::Function(_) => panic!("get type error"), Value::NoneValue => panic!("get type error"), } @@ -193,7 +193,7 @@ impl<'a> HirRunner<'a> { env.set_symbol(node_id, Value::Function(node_id)); } Signature::VariableSignature(_) => { - match self.symbol_table.get(node_id).body { + match self.symbol_table.get(node_id).decl_body { Some(body) => { let value = self.eval_expr(body, env)?; env.set_symbol(node_id, value); @@ -201,9 +201,7 @@ impl<'a> HirRunner<'a> { None => {} // variable is not defined yet } } - Signature::StructSignature(_) => { - env.set_symbol(node_id, Value::Struct(node_id)); - } + Signature::StructSignature(_) => {} } Ok(StatementResult::None) } @@ -314,7 +312,8 @@ impl<'a> HirRunner<'a> { | Node::ArithmeticOp(_) | Node::LogicalUnaryOp(_) | Node::CallExpr(_) - | Node::FieldAccess(_) => { + | Node::FieldAccess(_) + | Node::StructExpr(_) => { self.eval_expr(node_id, env)?; Ok(StatementResult::None) } @@ -322,7 +321,6 @@ impl<'a> HirRunner<'a> { | Node::Variable(_) | Node::FuncParam(_) | Node::StructDeclField(_) - | Node::StructExpr(_) | Node::StructExprField(_) => { panic!("Failed to execute the statement: unsupported node (node_id={})", node_id); } @@ -436,9 +434,9 @@ impl<'a> HirRunner<'a> { let callee_id = self.resolve_identifier(call_expr.callee); let callee = callee_id.get(self.source).as_decl().unwrap(); let signature = callee.signature.as_function_signature().unwrap(); - let func = match self.symbol_table.get(callee_id).body { + let func = match self.symbol_table.get(callee_id).decl_body { Some(x) => x.get(self.source).as_function().unwrap(), - None => panic!("function `{}` is not defined (node_id={})", callee.identifier, call_expr.callee), + None => panic!("function `{}` is not defined (node_id={})", callee.name, call_expr.callee), }; let mut args = Vec::new(); for &arg_id in call_expr.args.iter() { @@ -467,7 +465,7 @@ impl<'a> HirRunner<'a> { } } FunctionBody::NativeCode => { - result = Some(self.builtins.call(&callee.identifier, &args, self.source)?); + result = Some(self.builtins.call(&callee.name, &args, self.source)?); } } env.pop_frame(); @@ -477,8 +475,8 @@ impl<'a> HirRunner<'a> { }; Ok(value) } - Node::StructExpr(_struct_expr) => { - Ok(Value::Struct(node_id)) + Node::StructExpr(_expr) => { + todo!(); // TODO: 構造体のインスタンスを返す } Node::FieldAccess(_expr) => { todo!(); // TODO: 構造体のフィールドの値を取得して返す diff --git a/uguisu-engine/src/parse/test.rs b/uguisu-engine/src/parse/test.rs index effd4001..cea08186 100644 --- a/uguisu-engine/src/parse/test.rs +++ b/uguisu-engine/src/parse/test.rs @@ -147,20 +147,20 @@ fn test_declare_func_with_types_4() { #[test] fn test_identifier_single_ascii() { - if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("a") { - assert_eq!(identifier, "a"); + if let Ok(Node::Identifier(Identifier { name, pos: 0, .. })) = uguisu_parser::expression("a") { + assert_eq!(name, "a"); } else { panic!("incorrect result 1"); } - if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("z") { - assert_eq!(identifier, "z"); + if let Ok(Node::Identifier(Identifier { name, pos: 0, .. })) = uguisu_parser::expression("z") { + assert_eq!(name, "z"); } else { panic!("incorrect result 2"); } - if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("_") { - assert_eq!(identifier, "_"); + if let Ok(Node::Identifier(Identifier { name, pos: 0, .. })) = uguisu_parser::expression("_") { + assert_eq!(name, "_"); } else { panic!("incorrect result 3"); } @@ -172,8 +172,8 @@ fn test_identifier_single_ascii() { #[test] fn test_identifier_multi_ascii() { - if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("abc") { - assert_eq!(identifier, "abc"); + if let Ok(Node::Identifier(Identifier { name, pos: 0, .. })) = uguisu_parser::expression("abc") { + assert_eq!(name, "abc"); } else { panic!("incorrect result"); } @@ -185,14 +185,14 @@ fn test_identifier_multi_ascii() { #[test] fn test_identifier_multi_byte() { - if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("あ") { - assert_eq!(identifier, "あ"); + if let Ok(Node::Identifier(Identifier { name, pos: 0, .. })) = uguisu_parser::expression("あ") { + assert_eq!(name, "あ"); } else { panic!("incorrect result"); } - if let Ok(Node::Identifier(Identifier { value: identifier, pos: 0, .. })) = uguisu_parser::expression("変数1") { - assert_eq!(identifier, "変数1"); + if let Ok(Node::Identifier(Identifier { name, pos: 0, .. })) = uguisu_parser::expression("変数1") { + assert_eq!(name, "変数1"); } else { panic!("incorrect result"); }