From 4e096069ad7a751c22d6731726fe890cb5ef2387 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 8 Apr 2022 16:55:45 +0200 Subject: [PATCH] Super basic work on binder, rework of parser to include their spans --- src/binding/mod.rs | 5 + src/binding/type_registry.rs | 38 + src/integration_tests/add_function.rs | 265 +++-- src/integration_tests/build.rs | 3 +- .../class_with_many_statements.rs | 812 +++++++++------ .../empty_class_declaration.rs | 33 +- src/integration_tests/enum_definition.rs | 94 +- src/integration_tests/mod.rs | 3 +- .../multiple_inheritance_class.rs | 41 +- .../test_cases/add_function/parsed_tree.json | 264 +++-- .../parsed_tree.json | 812 +++++++++------ .../empty_class_declaration/parsed_tree.json | 32 +- .../enum_definition/parsed_tree.json | 94 +- .../parsed_tree.json | 40 +- src/lib.rs | 9 +- src/parsing/parser/mod.rs | 935 ++++++++++++------ src/parsing/parser/parsed_statement.rs | 24 +- src/parsing/parser/parser_tests.rs | 119 ++- src/types/mod.rs | 10 + src/types/script_type.rs | 33 + src/types/script_type_namespace.rs | 22 + src/types/type_library.rs | 22 + 22 files changed, 2504 insertions(+), 1206 deletions(-) create mode 100644 src/binding/mod.rs create mode 100644 src/binding/type_registry.rs create mode 100644 src/types/mod.rs create mode 100644 src/types/script_type.rs create mode 100644 src/types/script_type_namespace.rs create mode 100644 src/types/type_library.rs diff --git a/src/binding/mod.rs b/src/binding/mod.rs new file mode 100644 index 0000000..ea468c5 --- /dev/null +++ b/src/binding/mod.rs @@ -0,0 +1,5 @@ +use crate::parsing::parser::parsed_statement::ParsedStatement; + +mod type_registry; + +pub fn bind(_statement: Box) {} diff --git a/src/binding/type_registry.rs b/src/binding/type_registry.rs new file mode 100644 index 0000000..947ec7e --- /dev/null +++ b/src/binding/type_registry.rs @@ -0,0 +1,38 @@ +use crate::parsing::parser::parsed_statement::{ParsedStatement, ParsedStatementData}; +use crate::types::script_type::ScriptType; +use crate::types::script_type_namespace::ScriptTypeNamespace; +use crate::types::type_library::TypeLibrary; + +pub fn register_types(statement: &ParsedStatement) -> TypeLibrary { + let mut library = TypeLibrary::new(); + library = find_types_in_statement(statement, library, None); + + library +} + +fn find_types_in_statement( + statement: &ParsedStatement, + mut library: TypeLibrary, + active_namespace: Option, +) -> TypeLibrary { + match &statement.data { + ParsedStatementData::Script { statements } => { + for statement in statements { + library = find_types_in_statement(statement.as_ref(), library, None); + } + } + ParsedStatementData::ClassDeclaration { name, .. } => { + let script_type = ScriptType::new(); + + if let Some(mut ns) = active_namespace { + ns.register(name, script_type); + } else { + library + .get_global_namespace_mut() + .register(name, script_type); + }; + } + _ => {} + } + library +} diff --git a/src/integration_tests/add_function.rs b/src/integration_tests/add_function.rs index bdeaf99..682f220 100644 --- a/src/integration_tests/add_function.rs +++ b/src/integration_tests/add_function.rs @@ -257,102 +257,187 @@ fn integration_add_function() { println!("Parsed Tree JSON: {}", serde_json::to_string(&parsed_tree).unwrap()); let expected_tree: Box = serde_json::from_str(r#"{ + "data": { "Script": { - "statements": [ - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": false, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "name": "add", - "param_list": { - "ParamList": { - "parameters": [ - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "a", - "default": null - }, - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "b", - "default": null - } - ] - } - }, + "statements": [ + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": false, + "returns_reference": false, + "return_type": { + "data": { + "Type": { "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "ReturnStatement": { - "expression": { - "BinaryExpr": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "a" - } - }, - "operator": "Addition", - "right": { - "VarAccess": { - "scope": null, - "identifier": "b" - } - } - } - } - } - } - ] + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" } - } + }, + "span": { + "start": 0, + "end": 3 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 0, + "end": 3 } + }, + "name": "add", + "param_list": { + "data": { + "ParamList": { + "parameters": [ + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 8, + "end": 11 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 8, + "end": 11 + } + }, + "type_mod": null, + "identifier": "a", + "default": null + }, + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 15, + "end": 18 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 15, + "end": 18 + } + }, + "type_mod": null, + "identifier": "b", + "default": null + } + ] + } + }, + "span": { + "start": 7, + "end": 21 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "ReturnStatement": { + "expression": { + "data": { + "BinaryExpr": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "a" + } + }, + "span": { + "start": 35, + "end": 36 + } + }, + "operator": "Addition", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "b" + } + }, + "span": { + "start": 39, + "end": 40 + } + } + } + }, + "span": { + "start": 35, + "end": 40 + } + } + } + }, + "span": { + "start": 28, + "end": 41 + } + } + ] + } + }, + "span": { + "start": 22, + "end": 43 + } + } } - ] + }, + "span": { + "start": 0, + "end": 43 + } + } + ] } -}"#).unwrap(); + }, + "span": { + "start": 0, + "end": 43 + } +} +"#).unwrap(); assert_eq!(parsed_tree, expected_tree); } // A substring of a script should never panic, even though it might be completely invalid. diff --git a/src/integration_tests/build.rs b/src/integration_tests/build.rs index 196d1c3..5479399 100644 --- a/src/integration_tests/build.rs +++ b/src/integration_tests/build.rs @@ -12,7 +12,8 @@ fn main() { mod_file, r#"//////////////////////////// // Automatically Generated// -////////////////////////////"# +//////////////////////////// +"# ) .unwrap(); diff --git a/src/integration_tests/class_with_many_statements.rs b/src/integration_tests/class_with_many_statements.rs index bd2352e..64d1e21 100644 --- a/src/integration_tests/class_with_many_statements.rs +++ b/src/integration_tests/class_with_many_statements.rs @@ -44,290 +44,548 @@ fn integration_class_with_many_statements() { println!("Parsed Tree JSON: {}", serde_json::to_string(&parsed_tree).unwrap()); let expected_tree: Box = serde_json::from_str(r#"{ + "data": { "Script": { - "statements": [ - { - "ClassDeclaration": { - "modifiers": 10, - "name": "Foobar", - "inherits": [], - "statements": [ - { - "Var": { - "modifier": 0, - "var_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "identifier": "_a", - "assignment": null - } - }, - { - "Var": { - "modifier": 0, - "var_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "identifier": "_b", - "assignment": null - } - }, - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": true, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypeIdentifier": { - "identifier": "Foobar" - } - }, - "modifiers": [] - } - }, - "name": "Foobar", - "param_list": { - "ParamList": { - "parameters": [ - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "a", - "default": null - }, - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "b", - "default": null - } - ] - } - }, - "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "Assignment": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "_a" - } - }, - "operator": "Assignment", - "right": { - "VarAccess": { - "scope": null, - "identifier": "a" - } - } - } - }, - { - "Assignment": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "_b" - } - }, - "operator": "Assignment", - "right": { - "VarAccess": { - "scope": null, - "identifier": "b" - } - } - } - } - ] - } + "statements": [ + { + "data": { + "ClassDeclaration": { + "modifiers": 10, + "name": "Foobar", + "inherits": [], + "statements": [ + { + "data": { + "Var": { + "modifier": 0, + "var_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" } - } + }, + "span": { + "start": 32, + "end": 35 + } + }, + "modifiers": [] + } }, - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": false, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "name": "GetA", - "param_list": { - "ParamList": { - "parameters": [] - } - }, - "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "ReturnStatement": { - "expression": { - "VarAccess": { - "scope": null, - "identifier": "_a" - } - } - } - } - ] - } - } - } - }, - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": false, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "name": "Add", - "param_list": { - "ParamList": { - "parameters": [] - } - }, - "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "ReturnStatement": { - "expression": { - "BinaryExpr": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "_a" - } - }, - "operator": "Addition", - "right": { - "VarAccess": { - "scope": null, - "identifier": "_b" - } - } - } - } - } - } - ] - } - } - } - }, - { - "ClassDeclaration": { - "modifiers": 0, - "name": "Inner", - "inherits": [], - "statements": [ - { - "Var": { - "modifier": 0, - "var_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "identifier": "a", - "assignment": null - } - } - ] - } + "span": { + "start": 32, + "end": 35 } - ] + }, + "identifier": "_a", + "assignment": null + } + }, + "span": { + "start": 32, + "end": 39 + } + }, + { + "data": { + "Var": { + "modifier": 0, + "var_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 44, + "end": 47 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 44, + "end": 47 + } + }, + "identifier": "_b", + "assignment": null + } + }, + "span": { + "start": 44, + "end": 51 + } + }, + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": true, + "returns_reference": false, + "return_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypeIdentifier": { + "identifier": "Foobar" + } + }, + "span": { + "start": 57, + "end": 63 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 57, + "end": 63 + } + }, + "name": "Foobar", + "param_list": { + "data": { + "ParamList": { + "parameters": [ + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 64, + "end": 67 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 64, + "end": 67 + } + }, + "type_mod": null, + "identifier": "a", + "default": null + }, + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 71, + "end": 74 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 71, + "end": 74 + } + }, + "type_mod": null, + "identifier": "b", + "default": null + } + ] + } + }, + "span": { + "start": 63, + "end": 77 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "Assignment": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_a" + } + }, + "span": { + "start": 88, + "end": 90 + } + }, + "operator": "Assignment", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "a" + } + }, + "span": { + "start": 93, + "end": 94 + } + } + } + }, + "span": { + "start": 88, + "end": 94 + } + }, + { + "data": { + "Assignment": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_b" + } + }, + "span": { + "start": 104, + "end": 106 + } + }, + "operator": "Assignment", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "b" + } + }, + "span": { + "start": 109, + "end": 110 + } + } + } + }, + "span": { + "start": 104, + "end": 110 + } + } + ] + } + }, + "span": { + "start": 78, + "end": 117 + } + } + } + }, + "span": { + "start": 57, + "end": 117 + } + }, + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": false, + "returns_reference": false, + "return_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 123, + "end": 126 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 123, + "end": 126 + } + }, + "name": "GetA", + "param_list": { + "data": { + "ParamList": { + "parameters": [] + } + }, + "span": { + "start": 131, + "end": 133 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "ReturnStatement": { + "expression": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_a" + } + }, + "span": { + "start": 150, + "end": 152 + } + } + } + }, + "span": { + "start": 143, + "end": 153 + } + } + ] + } + }, + "span": { + "start": 133, + "end": 159 + } + } + } + }, + "span": { + "start": 123, + "end": 159 + } + }, + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": false, + "returns_reference": false, + "return_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 165, + "end": 168 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 165, + "end": 168 + } + }, + "name": "Add", + "param_list": { + "data": { + "ParamList": { + "parameters": [] + } + }, + "span": { + "start": 172, + "end": 174 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "ReturnStatement": { + "expression": { + "data": { + "BinaryExpr": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_a" + } + }, + "span": { + "start": 192, + "end": 194 + } + }, + "operator": "Addition", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_b" + } + }, + "span": { + "start": 197, + "end": 199 + } + } + } + }, + "span": { + "start": 192, + "end": 199 + } + } + } + }, + "span": { + "start": 185, + "end": 200 + } + } + ] + } + }, + "span": { + "start": 175, + "end": 206 + } + } + } + }, + "span": { + "start": 165, + "end": 206 + } + }, + { + "data": { + "ClassDeclaration": { + "modifiers": 0, + "name": "Inner", + "inherits": [], + "statements": [ + { + "data": { + "Var": { + "modifier": 0, + "var_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 234, + "end": 237 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 234, + "end": 237 + } + }, + "identifier": "a", + "assignment": null + } + }, + "span": { + "start": 234, + "end": 240 + } + } + ] + } + }, + "span": { + "start": 212, + "end": 246 + } } + ] } - ] + }, + "span": { + "start": 0, + "end": 248 + } + } + ] } + }, + "span": { + "start": 0, + "end": 248 + } }"#).unwrap(); assert_eq!(parsed_tree, expected_tree); } diff --git a/src/integration_tests/empty_class_declaration.rs b/src/integration_tests/empty_class_declaration.rs index 93af9e8..0da0ddc 100644 --- a/src/integration_tests/empty_class_declaration.rs +++ b/src/integration_tests/empty_class_declaration.rs @@ -79,19 +79,32 @@ fn integration_empty_class_declaration() { println!("Parsed Tree JSON: {}", serde_json::to_string(&parsed_tree).unwrap()); let expected_tree: Box = serde_json::from_str(r#"{ + "data": { "Script": { - "statements": [ - { - "ClassDeclaration": { - "modifiers": 0, - "name": "Foo", - "inherits": [], - "statements": [] - } + "statements": [ + { + "data": { + "ClassDeclaration": { + "modifiers": 0, + "name": "Foo", + "inherits": [], + "statements": [] } - ] + }, + "span": { + "start": 0, + "end": 12 + } + } + ] } -}"#).unwrap(); + }, + "span": { + "start": 0, + "end": 12 + } +} +"#).unwrap(); assert_eq!(parsed_tree, expected_tree); } // A substring of a script should never panic, even though it might be completely invalid. diff --git a/src/integration_tests/enum_definition.rs b/src/integration_tests/enum_definition.rs index 9a2178b..9f55a41 100644 --- a/src/integration_tests/enum_definition.rs +++ b/src/integration_tests/enum_definition.rs @@ -398,45 +398,69 @@ fn integration_enum_definition() { println!("Parsed Tree JSON: {}", serde_json::to_string(&parsed_tree).unwrap()); let expected_tree: Box = serde_json::from_str(r#"{ + "data": { "Script": { - "statements": [ - { - "EnumDeclaration": { - "modifiers": 0, - "identifier": "TestEnum", - "base_type": { - "DataTypePrimType": { - "prim_type": "UInt8" - } - }, - "values": [ - [ - "a", - null - ], - [ - "b", - null - ], - [ - "c", - null - ], - [ - "d", - { - "IntegerLiteral": 128 - } - ], - [ - "e", - null - ] - ] + "statements": [ + { + "data": { + "EnumDeclaration": { + "modifiers": 0, + "identifier": "TestEnum", + "base_type": { + "data": { + "DataTypePrimType": { + "prim_type": "UInt8" + } + }, + "span": { + "start": 16, + "end": 21 } + }, + "values": [ + [ + "a", + null + ], + [ + "b", + null + ], + [ + "c", + null + ], + [ + "d", + { + "data": { + "IntegerLiteral": 128 + }, + "span": { + "start": 53, + "end": 56 + } + } + ], + [ + "e", + null + ] + ] } - ] + }, + "span": { + "start": 0, + "end": 65 + } + } + ] } + }, + "span": { + "start": 0, + "end": 65 + } }"#).unwrap(); assert_eq!(parsed_tree, expected_tree); } diff --git a/src/integration_tests/mod.rs b/src/integration_tests/mod.rs index 91f9dd1..e181099 100644 --- a/src/integration_tests/mod.rs +++ b/src/integration_tests/mod.rs @@ -1,6 +1,7 @@ //////////////////////////// // Automatically Generated// -////////////////////////////mod enum_definition; +//////////////////////////// +mod enum_definition; mod multiple_inheritance_class; mod empty_class_declaration; mod class_with_many_statements; diff --git a/src/integration_tests/multiple_inheritance_class.rs b/src/integration_tests/multiple_inheritance_class.rs index ffc9dcb..43d06de 100644 --- a/src/integration_tests/multiple_inheritance_class.rs +++ b/src/integration_tests/multiple_inheritance_class.rs @@ -155,23 +155,36 @@ fn integration_multiple_inheritance_class() { println!("Parsed Tree JSON: {}", serde_json::to_string(&parsed_tree).unwrap()); let expected_tree: Box = serde_json::from_str(r#"{ + "data": { "Script": { - "statements": [ - { - "ClassDeclaration": { - "modifiers": 0, - "name": "Foo", - "inherits": [ - "Zom", - "Aar", - "Bar" - ], - "statements": [] - } + "statements": [ + { + "data": { + "ClassDeclaration": { + "modifiers": 0, + "name": "Foo", + "inherits": [ + "Zom", + "Aar", + "Bar" + ], + "statements": [] } - ] + }, + "span": { + "start": 0, + "end": 28 + } + } + ] } -}"#).unwrap(); + }, + "span": { + "start": 0, + "end": 28 + } +} +"#).unwrap(); assert_eq!(parsed_tree, expected_tree); } // A substring of a script should never panic, even though it might be completely invalid. diff --git a/src/integration_tests/test_cases/add_function/parsed_tree.json b/src/integration_tests/test_cases/add_function/parsed_tree.json index dc6ed93..f5d1e87 100644 --- a/src/integration_tests/test_cases/add_function/parsed_tree.json +++ b/src/integration_tests/test_cases/add_function/parsed_tree.json @@ -1,97 +1,181 @@ { + "data": { "Script": { - "statements": [ - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": false, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "name": "add", - "param_list": { - "ParamList": { - "parameters": [ - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "a", - "default": null - }, - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "b", - "default": null - } - ] - } - }, + "statements": [ + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": false, + "returns_reference": false, + "return_type": { + "data": { + "Type": { "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "ReturnStatement": { - "expression": { - "BinaryExpr": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "a" - } - }, - "operator": "Addition", - "right": { - "VarAccess": { - "scope": null, - "identifier": "b" - } - } - } - } - } - } - ] + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" } - } + }, + "span": { + "start": 0, + "end": 3 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 0, + "end": 3 } + }, + "name": "add", + "param_list": { + "data": { + "ParamList": { + "parameters": [ + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 8, + "end": 11 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 8, + "end": 11 + } + }, + "type_mod": null, + "identifier": "a", + "default": null + }, + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 15, + "end": 18 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 15, + "end": 18 + } + }, + "type_mod": null, + "identifier": "b", + "default": null + } + ] + } + }, + "span": { + "start": 7, + "end": 21 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "ReturnStatement": { + "expression": { + "data": { + "BinaryExpr": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "a" + } + }, + "span": { + "start": 35, + "end": 36 + } + }, + "operator": "Addition", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "b" + } + }, + "span": { + "start": 39, + "end": 40 + } + } + } + }, + "span": { + "start": 35, + "end": 40 + } + } + } + }, + "span": { + "start": 28, + "end": 41 + } + } + ] + } + }, + "span": { + "start": 22, + "end": 43 + } + } } - ] + }, + "span": { + "start": 0, + "end": 43 + } + } + ] } -} \ No newline at end of file + }, + "span": { + "start": 0, + "end": 43 + } +} diff --git a/src/integration_tests/test_cases/class_with_many_statements/parsed_tree.json b/src/integration_tests/test_cases/class_with_many_statements/parsed_tree.json index bfafabb..43f9ace 100644 --- a/src/integration_tests/test_cases/class_with_many_statements/parsed_tree.json +++ b/src/integration_tests/test_cases/class_with_many_statements/parsed_tree.json @@ -1,286 +1,544 @@ { + "data": { "Script": { - "statements": [ - { - "ClassDeclaration": { - "modifiers": 10, - "name": "Foobar", - "inherits": [], - "statements": [ - { - "Var": { - "modifier": 0, - "var_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "identifier": "_a", - "assignment": null - } - }, - { - "Var": { - "modifier": 0, - "var_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "identifier": "_b", - "assignment": null - } - }, - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": true, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypeIdentifier": { - "identifier": "Foobar" - } - }, - "modifiers": [] - } - }, - "name": "Foobar", - "param_list": { - "ParamList": { - "parameters": [ - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "a", - "default": null - }, - { - "parameter_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "type_mod": null, - "identifier": "b", - "default": null - } - ] - } - }, - "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "Assignment": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "_a" - } - }, - "operator": "Assignment", - "right": { - "VarAccess": { - "scope": null, - "identifier": "a" - } - } - } - }, - { - "Assignment": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "_b" - } - }, - "operator": "Assignment", - "right": { - "VarAccess": { - "scope": null, - "identifier": "b" - } - } - } - } - ] - } + "statements": [ + { + "data": { + "ClassDeclaration": { + "modifiers": 10, + "name": "Foobar", + "inherits": [], + "statements": [ + { + "data": { + "Var": { + "modifier": 0, + "var_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" } - } + }, + "span": { + "start": 32, + "end": 35 + } + }, + "modifiers": [] + } }, - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": false, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "name": "GetA", - "param_list": { - "ParamList": { - "parameters": [] - } - }, - "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "ReturnStatement": { - "expression": { - "VarAccess": { - "scope": null, - "identifier": "_a" - } - } - } - } - ] - } - } - } - }, - { - "FuncDeclaration": { - "modifiers": 0, - "field_mod": null, - "is_destructor": false, - "is_constructor": false, - "returns_reference": false, - "return_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "name": "Add", - "param_list": { - "ParamList": { - "parameters": [] - } - }, - "is_const": false, - "func_attr": 0, - "block": { - "StatBlock": { - "statements": [ - { - "ReturnStatement": { - "expression": { - "BinaryExpr": { - "left": { - "VarAccess": { - "scope": null, - "identifier": "_a" - } - }, - "operator": "Addition", - "right": { - "VarAccess": { - "scope": null, - "identifier": "_b" - } - } - } - } - } - } - ] - } - } - } - }, - { - "ClassDeclaration": { - "modifiers": 0, - "name": "Inner", - "inherits": [], - "statements": [ - { - "Var": { - "modifier": 0, - "var_type": { - "Type": { - "is_const": false, - "scope": null, - "datatype": { - "DataTypePrimType": { - "prim_type": "Int32" - } - }, - "modifiers": [] - } - }, - "identifier": "a", - "assignment": null - } - } - ] - } + "span": { + "start": 32, + "end": 35 } - ] + }, + "identifier": "_a", + "assignment": null + } + }, + "span": { + "start": 32, + "end": 39 + } + }, + { + "data": { + "Var": { + "modifier": 0, + "var_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 44, + "end": 47 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 44, + "end": 47 + } + }, + "identifier": "_b", + "assignment": null + } + }, + "span": { + "start": 44, + "end": 51 + } + }, + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": true, + "returns_reference": false, + "return_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypeIdentifier": { + "identifier": "Foobar" + } + }, + "span": { + "start": 57, + "end": 63 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 57, + "end": 63 + } + }, + "name": "Foobar", + "param_list": { + "data": { + "ParamList": { + "parameters": [ + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 64, + "end": 67 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 64, + "end": 67 + } + }, + "type_mod": null, + "identifier": "a", + "default": null + }, + { + "parameter_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 71, + "end": 74 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 71, + "end": 74 + } + }, + "type_mod": null, + "identifier": "b", + "default": null + } + ] + } + }, + "span": { + "start": 63, + "end": 77 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "Assignment": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_a" + } + }, + "span": { + "start": 88, + "end": 90 + } + }, + "operator": "Assignment", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "a" + } + }, + "span": { + "start": 93, + "end": 94 + } + } + } + }, + "span": { + "start": 88, + "end": 94 + } + }, + { + "data": { + "Assignment": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_b" + } + }, + "span": { + "start": 104, + "end": 106 + } + }, + "operator": "Assignment", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "b" + } + }, + "span": { + "start": 109, + "end": 110 + } + } + } + }, + "span": { + "start": 104, + "end": 110 + } + } + ] + } + }, + "span": { + "start": 78, + "end": 117 + } + } + } + }, + "span": { + "start": 57, + "end": 117 + } + }, + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": false, + "returns_reference": false, + "return_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 123, + "end": 126 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 123, + "end": 126 + } + }, + "name": "GetA", + "param_list": { + "data": { + "ParamList": { + "parameters": [] + } + }, + "span": { + "start": 131, + "end": 133 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "ReturnStatement": { + "expression": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_a" + } + }, + "span": { + "start": 150, + "end": 152 + } + } + } + }, + "span": { + "start": 143, + "end": 153 + } + } + ] + } + }, + "span": { + "start": 133, + "end": 159 + } + } + } + }, + "span": { + "start": 123, + "end": 159 + } + }, + { + "data": { + "FuncDeclaration": { + "modifiers": 0, + "field_mod": null, + "is_destructor": false, + "is_constructor": false, + "returns_reference": false, + "return_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 165, + "end": 168 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 165, + "end": 168 + } + }, + "name": "Add", + "param_list": { + "data": { + "ParamList": { + "parameters": [] + } + }, + "span": { + "start": 172, + "end": 174 + } + }, + "is_const": false, + "func_attr": 0, + "block": { + "data": { + "StatBlock": { + "statements": [ + { + "data": { + "ReturnStatement": { + "expression": { + "data": { + "BinaryExpr": { + "left": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_a" + } + }, + "span": { + "start": 192, + "end": 194 + } + }, + "operator": "Addition", + "right": { + "data": { + "VarAccess": { + "scope": null, + "identifier": "_b" + } + }, + "span": { + "start": 197, + "end": 199 + } + } + } + }, + "span": { + "start": 192, + "end": 199 + } + } + } + }, + "span": { + "start": 185, + "end": 200 + } + } + ] + } + }, + "span": { + "start": 175, + "end": 206 + } + } + } + }, + "span": { + "start": 165, + "end": 206 + } + }, + { + "data": { + "ClassDeclaration": { + "modifiers": 0, + "name": "Inner", + "inherits": [], + "statements": [ + { + "data": { + "Var": { + "modifier": 0, + "var_type": { + "data": { + "Type": { + "is_const": false, + "scope": null, + "datatype": { + "data": { + "DataTypePrimType": { + "prim_type": "Int32" + } + }, + "span": { + "start": 234, + "end": 237 + } + }, + "modifiers": [] + } + }, + "span": { + "start": 234, + "end": 237 + } + }, + "identifier": "a", + "assignment": null + } + }, + "span": { + "start": 234, + "end": 240 + } + } + ] + } + }, + "span": { + "start": 212, + "end": 246 + } } + ] } - ] + }, + "span": { + "start": 0, + "end": 248 + } + } + ] } + }, + "span": { + "start": 0, + "end": 248 + } } \ No newline at end of file diff --git a/src/integration_tests/test_cases/empty_class_declaration/parsed_tree.json b/src/integration_tests/test_cases/empty_class_declaration/parsed_tree.json index 411e062..6c954aa 100644 --- a/src/integration_tests/test_cases/empty_class_declaration/parsed_tree.json +++ b/src/integration_tests/test_cases/empty_class_declaration/parsed_tree.json @@ -1,14 +1,26 @@ { + "data": { "Script": { - "statements": [ - { - "ClassDeclaration": { - "modifiers": 0, - "name": "Foo", - "inherits": [], - "statements": [] - } + "statements": [ + { + "data": { + "ClassDeclaration": { + "modifiers": 0, + "name": "Foo", + "inherits": [], + "statements": [] } - ] + }, + "span": { + "start": 0, + "end": 12 + } + } + ] } -} \ No newline at end of file + }, + "span": { + "start": 0, + "end": 12 + } +} diff --git a/src/integration_tests/test_cases/enum_definition/parsed_tree.json b/src/integration_tests/test_cases/enum_definition/parsed_tree.json index f8f2d10..b8ba3f8 100644 --- a/src/integration_tests/test_cases/enum_definition/parsed_tree.json +++ b/src/integration_tests/test_cases/enum_definition/parsed_tree.json @@ -1,41 +1,65 @@ { + "data": { "Script": { - "statements": [ - { - "EnumDeclaration": { - "modifiers": 0, - "identifier": "TestEnum", - "base_type": { - "DataTypePrimType": { - "prim_type": "UInt8" - } - }, - "values": [ - [ - "a", - null - ], - [ - "b", - null - ], - [ - "c", - null - ], - [ - "d", - { - "IntegerLiteral": 128 - } - ], - [ - "e", - null - ] - ] + "statements": [ + { + "data": { + "EnumDeclaration": { + "modifiers": 0, + "identifier": "TestEnum", + "base_type": { + "data": { + "DataTypePrimType": { + "prim_type": "UInt8" + } + }, + "span": { + "start": 16, + "end": 21 } + }, + "values": [ + [ + "a", + null + ], + [ + "b", + null + ], + [ + "c", + null + ], + [ + "d", + { + "data": { + "IntegerLiteral": 128 + }, + "span": { + "start": 53, + "end": 56 + } + } + ], + [ + "e", + null + ] + ] } - ] + }, + "span": { + "start": 0, + "end": 65 + } + } + ] } + }, + "span": { + "start": 0, + "end": 65 + } } \ No newline at end of file diff --git a/src/integration_tests/test_cases/multiple_inheritance_class/parsed_tree.json b/src/integration_tests/test_cases/multiple_inheritance_class/parsed_tree.json index bd83aec..617c366 100644 --- a/src/integration_tests/test_cases/multiple_inheritance_class/parsed_tree.json +++ b/src/integration_tests/test_cases/multiple_inheritance_class/parsed_tree.json @@ -1,18 +1,30 @@ { + "data": { "Script": { - "statements": [ - { - "ClassDeclaration": { - "modifiers": 0, - "name": "Foo", - "inherits": [ - "Zom", - "Aar", - "Bar" - ], - "statements": [] - } + "statements": [ + { + "data": { + "ClassDeclaration": { + "modifiers": 0, + "name": "Foo", + "inherits": [ + "Zom", + "Aar", + "Bar" + ], + "statements": [] } - ] + }, + "span": { + "start": 0, + "end": 28 + } + } + ] } -} \ No newline at end of file + }, + "span": { + "start": 0, + "end": 28 + } +} diff --git a/src/lib.rs b/src/lib.rs index 08a09bd..66bda2a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,15 +4,18 @@ #![feature(fn_traits)] #![feature(iter_advance_by)] #![feature(backtrace)] +#![feature(in_band_lifetimes)] extern crate core; +#[cfg(test)] +mod integration_tests; + +pub mod binding; pub mod defines; pub mod logger; pub mod modifiers; pub mod parsing; pub(crate) mod prim_type; pub mod span; - -#[cfg(test)] -mod integration_tests; +pub mod types; diff --git a/src/parsing/parser/mod.rs b/src/parsing/parser/mod.rs index bb56c1a..42fb055 100644 --- a/src/parsing/parser/mod.rs +++ b/src/parsing/parser/mod.rs @@ -10,10 +10,7 @@ use crate::logger::messages::Message; use crate::logger::messages::Message::UnexpectedToken; use crate::modifiers::{FieldModifier, TypeModifier}; use crate::parsing::parser::parsed_funcattr::FuncAttr; -use crate::parsing::parser::parsed_statement::ParsedParameter; -use crate::parsing::parser::parsed_statement::ParsedStatement::{ - AnonymousCall, ExprPostOp, IndexingOperator, -}; +use crate::parsing::parser::parsed_statement::{ParsedParameter, ParsedStatementData}; use crate::parsing::parser::parsed_type_modifier::{ParsedTypeModifier, ReferenceModifier}; use crate::parsing::parser::parser_operators::{ BinaryOperator, PostOperator, PreOperator, TernaryOperator, @@ -144,41 +141,42 @@ fn parse_script( log: &mut dyn FnMut(Message, Span), ) -> Box { // script ::= {import | enum | typedef | class | interface | funcdef | virtprop | var | func | namespace | ';'}; - let mut vec: Vec = Vec::new(); + let mut vec: Vec> = Vec::new(); + let start = reader.peek().span.start; loop { let n = reader.peek(); let token_type = n.token_type.clone(); let span = n.span; match token_type { TokenType::ImportKeyword => { - vec.push(*parse_import(reader, log).unwrap()); + vec.push(parse_import(reader, log).unwrap()); } TokenType::TypeDefKeyword => { - vec.push(*parse_typedef(reader, log).unwrap()); + vec.push(parse_typedef(reader, log).unwrap()); } TokenType::FuncDefKeyword => { - vec.push(*parse_funcdef(reader, log).unwrap()); + vec.push(parse_funcdef(reader, log).unwrap()); } TokenType::NamespaceKeyword => { - vec.push(*parse_namespace(reader, log)); + vec.push(parse_namespace(reader, log)); } - TokenType::InterfaceKeyword => vec.push(*parse_interface(reader, log).unwrap()), - TokenType::EnumKeyword => vec.push(*parse_enum(reader, log).unwrap()), + TokenType::InterfaceKeyword => vec.push(parse_interface(reader, log).unwrap()), + TokenType::EnumKeyword => vec.push(parse_enum(reader, log).unwrap()), TokenType::EndOfFile => break, TokenType::CloseCurlyBracket => break, _ => { if let Some(s) = parse_enum(reader, log) { - vec.push(*s); + vec.push(s); } else if let Some(s) = parse_class(reader, log) { - vec.push(*s); + vec.push(s); } else if let Some(s) = parse_interface(reader, log) { - vec.push(*s); + vec.push(s); } else if let Some(s) = parse_virtprop(reader, log) { - vec.push(*s); + vec.push(s); } else if let Some(s) = parse_var(reader, log) { - vec.push(*s); + vec.push(s); } else if let Some(s) = parse_func(reader, log) { - vec.push(*s); + vec.push(s); } else { log( UnexpectedToken { @@ -192,25 +190,45 @@ fn parse_script( } } } + let mut end = start; + if !vec.is_empty() { + end = vec.last().unwrap().span.end; + } - Box::new(ParsedStatement::Script { statements: vec }) + Box::new(ParsedStatement { + data: ParsedStatementData::Script { statements: vec }, + span: Span { start, end }, + }) } fn parse_namespace( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Box { + let start = reader.peek().span.start; reader.next(); // Consume namespace let identifier = parse_identifier(reader, log, false); if identifier.is_none() { - return Box::new(ParsedStatement::Invalid); + return Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: reader.peek().span.end, + }, + }); } reader.consume(TokenType::OpenCurlyBracket, log); let script = parse_script(reader, log); - reader.consume(TokenType::CloseCurlyBracket, log); - Box::new(ParsedStatement::Namespace { - identifier: identifier.unwrap(), - script, + let end_token = reader.consume(TokenType::CloseCurlyBracket, log); + Box::new(ParsedStatement { + data: ParsedStatementData::Namespace { + identifier: identifier.unwrap(), + script, + }, + span: Span { + start, + end: end_token.span.end, + }, }) } @@ -219,7 +237,7 @@ fn parse_interface( log: &mut dyn FnMut(Message, Span), ) -> Option> { // interface ::= {'external' | 'shared'} 'interface' identifier (';' | ([':' identifier {',' identifier}] '{' {virtprop | interfacemethod} '}')); - + let start = outer_reader.peek().span.start; let mut type_mod: BitFlags = BitFlags::empty(); let identifier: Option; let mut has_interface_keyword = false; @@ -243,21 +261,33 @@ fn parse_interface( if !has_interface_keyword { return None; } - let mut statements: Vec = Vec::new(); + let mut statements: Vec> = Vec::new(); let mut inherits: Vec = Vec::new(); loop { let t = reader.peek(); match t.token_type { TokenType::Semicolon => { - reader.next(); + let last = reader.next(); if identifier.is_none() { - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: last.span.end, + }, + })); } - return Some(Box::new(ParsedStatement::Interface { - type_mod, - identifier: identifier.unwrap(), - inherits, - statements, + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Interface { + type_mod, + identifier: identifier.unwrap(), + inherits, + statements, + }, + span: Span { + start, + end: last.span.end, + }, })); } TokenType::Colon | TokenType::OpenCurlyBracket => break, @@ -273,7 +303,13 @@ fn parse_interface( }, t.span, ); - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: t.span.end, + }, + })); } _ => { log( @@ -316,20 +352,26 @@ fn parse_interface( break; } } - statements.push(*prop.unwrap()); + statements.push(prop.unwrap()); } - reader.consume(TokenType::CloseCurlyBracket, log); + let end = reader.consume(TokenType::CloseCurlyBracket, log).span.end; outer_reader.set_from_inner(&reader); if identifier.is_none() { - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { start, end }, + })); } - Some(Box::new(ParsedStatement::Interface { - type_mod, - identifier: identifier.unwrap(), - inherits, - statements, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Interface { + type_mod, + identifier: identifier.unwrap(), + inherits, + statements, + }, + span: Span { start, end }, })) } @@ -338,6 +380,7 @@ fn parse_interface_method( log: &mut dyn FnMut(Message, Span), ) -> Option> { // interfacemethod ::= type ['&'] identifier paramlist ['const'] ';'; + let start = outer_reader.peek().span.start; let mut reader = outer_reader.create_inner(); let return_type = parse_type(&mut reader, log); return_type.as_ref()?; @@ -353,15 +396,19 @@ fn parse_interface_method( if is_const { reader.next(); } - reader.consume(TokenType::Semicolon, log); + let end = reader.consume(TokenType::Semicolon, log).span.end; outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::InterfaceMethod { - return_type: return_type.unwrap(), - returns_reference, - identifier: identifier.unwrap(), - param_list: param_list.unwrap(), - is_const, + + Some(Box::new(ParsedStatement { + data: ParsedStatementData::InterfaceMethod { + return_type: return_type.unwrap(), + returns_reference, + identifier: identifier.unwrap(), + param_list: param_list.unwrap(), + is_const, + }, + span: Span { start, end }, })) } @@ -373,26 +420,39 @@ fn parse_typedef( if reader.peek().token_type != TokenType::TypeDefKeyword { return None; } - reader.next(); + let start = reader.next().span.start; let mut left_type = parse_primtype(reader, log); if left_type.is_none() { + let span = reader.peek().span; let left_type_identifier = parse_identifier(reader, log, false); if let Some(s) = left_type_identifier { - left_type = Some(Box::new(ParsedStatement::DataTypeIdentifier { - identifier: s, + left_type = Some(Box::new(ParsedStatement { + data: ParsedStatementData::DataTypeIdentifier { identifier: s }, + span, })); } } + let span = reader.peek().span; let right_type_identifier = parse_identifier(reader, log, false); right_type_identifier.as_ref()?; - let right_type = Box::new(ParsedStatement::DataTypeIdentifier { - identifier: right_type_identifier.unwrap(), - }); + let right_type = Some(Box::new(ParsedStatement { + data: ParsedStatementData::DataTypeIdentifier { + identifier: right_type_identifier.unwrap(), + }, + span, + })); - reader.consume(TokenType::Semicolon, log); - Some(Box::new(ParsedStatement::TypeDefStatement { - from: left_type.unwrap(), - to: right_type, + let last = reader.consume(TokenType::Semicolon, log); + + Some(Box::new(ParsedStatement { + data: ParsedStatementData::TypeDefStatement { + from: left_type.unwrap(), + to: right_type.unwrap(), + }, + span: Span { + start, + end: last.span.end, + }, })) } @@ -404,7 +464,7 @@ fn parse_import( if reader.peek().token_type != TokenType::ImportKeyword { return None; } - reader.next(); + let start = reader.next().span.start; let import_type = parse_type(reader, log); let is_reference_type = reader.peek().token_type == TokenType::Ampersand; if is_reference_type { @@ -430,15 +490,21 @@ fn parse_import( ); return None; } - reader.consume(TokenType::Semicolon, log); + let last = reader.consume(TokenType::Semicolon, log); - Some(Box::new(ParsedStatement::ImportStatement { - import_type: import_type.unwrap(), - is_reference: is_reference_type, - identifier: identifier.unwrap(), - param_list: param_list.unwrap(), - func_attr, - source: source.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ImportStatement { + import_type: import_type.unwrap(), + is_reference: is_reference_type, + identifier: identifier.unwrap(), + param_list: param_list.unwrap(), + func_attr, + source: source.unwrap(), + }, + span: Span { + start, + end: last.span.end, + }, })) } @@ -447,6 +513,7 @@ fn parse_enum( log: &mut dyn FnMut(Message, Span), ) -> Option> { // enum ::= {'shared' | 'external'} 'enum' identifier [ ':' primtype ] (';' | ('{' identifier ['=' expr] {',' identifier ['=' expr]} '}')); + let start = reader.peek().span.start; let mut inner_reader = reader.create_inner(); let mut modifiers: BitFlags = BitFlags::empty(); loop { @@ -472,7 +539,13 @@ fn parse_enum( reader.set_from_inner(&inner_reader); let name = parse_identifier(reader, log, false); if name.is_none() { - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: reader.peek().span.end, + }, + })); } let mut base_type = None; if reader.peek().token_type == TokenType::Colon { @@ -487,13 +560,20 @@ fn parse_enum( }, reader.peek().span, ); - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: reader.peek().span.end, + }, + })); } base_type = prim_type; } let mut values = Vec::new(); + let end; if reader.peek().token_type == TokenType::OpenCurlyBracket { reader.next(); loop { @@ -515,14 +595,25 @@ fn parse_enum( } reader.next(); } - reader.consume(TokenType::CloseCurlyBracket, log); + end = reader.consume(TokenType::CloseCurlyBracket, log).span.end; + } else { + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: reader.peek().span.end, + }, + })); } - Some(Box::new(ParsedStatement::EnumDeclaration { - modifiers, - identifier: name.unwrap(), - base_type, - values, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::EnumDeclaration { + modifiers, + identifier: name.unwrap(), + base_type, + values, + }, + span: Span { start, end }, })) } @@ -532,6 +623,7 @@ fn parse_class( ) -> Option> { // class ::= {'shared' | 'abstract' | 'final' | 'external' | 'mixin'} 'class' identifier // (';' | ([':' identifier {',' identifier}] '{' {virtprop | func | var | funcdef | class} '}')); + let start = reader.peek().span.start; let mut inner_reader = reader.create_inner(); let mut modifiers: BitFlags = BitFlags::empty(); loop { @@ -617,17 +709,29 @@ fn parse_class( break; } } - reader.consume(TokenType::CloseCurlyBracket, log); + let last = reader.consume(TokenType::CloseCurlyBracket, log); if name.is_none() { - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start, + end: last.span.end, + }, + })); } - Some(Box::new(ParsedStatement::ClassDeclaration { - modifiers, - name: name.unwrap(), - inherits, - statements, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ClassDeclaration { + modifiers, + name: name.unwrap(), + inherits, + statements, + }, + span: Span { + start, + end: last.span.end, + }, })) } @@ -637,6 +741,7 @@ fn parse_funcdef( ) -> Option> { // funcdef ::= {'external' | 'shared'} 'funcdef' type ['&'] identifier paramlist ';' let mut reader = outer_reader.create_inner(); + let start = reader.peek().span.start; let mut modifiers: BitFlags = BitFlags::empty(); loop { match reader.peek().token_type { @@ -670,20 +775,26 @@ fn parse_funcdef( if reader.peek().token_type != TokenType::Semicolon { return None; } - reader.next(); + let end = reader.next().span.end; outer_reader.set_from_inner(&reader); if identifier.is_none() || param_list.is_none() { - Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { start, end }, + })); } - Some(Box::new(ParsedStatement::FuncDefDeclaration { - modifiers, - returns_reference, - return_type, - name: identifier.unwrap(), - param_list: param_list.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::FuncDefDeclaration { + modifiers, + returns_reference, + return_type, + name: identifier.unwrap(), + param_list: param_list.unwrap(), + }, + span: Span { start, end }, })) } @@ -692,6 +803,7 @@ fn parse_func( log: &mut dyn FnMut(Message, Span), ) -> Option> { // func ::= {'shared' | 'external'} ['private' | 'protected'] [((type ['&']) | '~')] identifier paramlist ['const'] funcattr (';' | statblock); + let start = outer_reader.peek().span.start; let mut reader = outer_reader.create_inner(); let mut modifiers: BitFlags = BitFlags::empty(); loop { @@ -742,8 +854,8 @@ fn parse_func( let mut is_constructor = false; if name.is_none() && return_type.is_some() { - if let ParsedStatement::Type { datatype, .. } = return_type.as_ref().unwrap().as_ref() { - if let ParsedStatement::DataTypeIdentifier { identifier } = datatype.as_ref() { + if let ParsedStatementData::Type { datatype, .. } = &return_type.as_ref().unwrap().data { + if let ParsedStatementData::DataTypeIdentifier { identifier } = &datatype.data { name = Some(identifier.to_string()); is_constructor = true; } @@ -760,25 +872,32 @@ fn parse_func( let func_attr = parse_funcattr(&mut reader, log); let mut block = None; + let mut end = start; if reader.peek().token_type == TokenType::Semicolon { - reader.next(); + end = reader.next().span.end; } else { block = parse_statblock(&mut reader, log); + if let Some(s) = &block { + end = s.span.end; + } } outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::FuncDeclaration { - modifiers, - field_mod, - is_destructor, - is_constructor, - returns_reference, - return_type, - name: name.unwrap(), - param_list: param_list.unwrap(), - is_const, - func_attr, - block, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::FuncDeclaration { + modifiers, + field_mod, + is_destructor, + is_constructor, + returns_reference, + return_type, + name: name.unwrap(), + param_list: param_list.unwrap(), + is_const, + func_attr, + block, + }, + span: Span { start, end }, })) } @@ -787,6 +906,7 @@ fn parse_virtprop( log: &mut dyn FnMut(Message, Span), ) -> Option> { // virtprop ::= ['private' | 'protected'] type ['&'] identifier '{' {('get' | 'set') ['const'] funcattr (statblock | ';')} '}'; + let start = outer_reader.peek().span.start; let mut reader = outer_reader.create_inner(); let mut field_mod: Option = None; match reader.peek().token_type { @@ -862,6 +982,7 @@ fn parse_virtprop( } let next = reader.next(); + let end = next.span.end; if next.token_type != TokenType::CloseCurlyBracket { return None; } @@ -876,20 +997,22 @@ fn parse_virtprop( } outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::VirtProp { - field_mod, - property_type: property_type.unwrap(), - identifier: identifier.unwrap(), - is_handle, - has_get, - is_get_const, - get_statement, - has_set, - is_set_const, - set_statement, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::VirtProp { + field_mod, + property_type: property_type.unwrap(), + identifier: identifier.unwrap(), + is_handle, + has_get, + is_get_const, + get_statement, + has_set, + is_set_const, + set_statement, + }, + span: Span { start, end }, })) } - fn parse_paramlist( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), @@ -898,13 +1021,19 @@ fn parse_paramlist( if reader.peek().token_type != TokenType::OpenBracket { return None; } - reader.next(); + let start = reader.next().span.start; // (void) is equivalent to () if reader.peek().token_type == TokenType::VoidKeyword { reader.next(); - reader.consume(TokenType::CloseBracket, log); - return Some(Box::new(ParsedStatement::ParamList { parameters: vec![] })); + let last = reader.consume(TokenType::CloseBracket, log); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::ParamList { parameters: vec![] }, + span: Span { + start, + end: last.span.end, + }, + })); } let mut params = Vec::new(); @@ -939,8 +1068,14 @@ fn parse_paramlist( } reader.next(); } - reader.consume(TokenType::CloseBracket, log); - Some(Box::new(ParsedStatement::ParamList { parameters: params })) + let last = reader.consume(TokenType::CloseBracket, log); + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ParamList { parameters: params }, + span: Span { + start, + end: last.span.end, + }, + })) } fn parse_funcattr( @@ -970,7 +1105,7 @@ fn parse_statblock( if reader.peek().token_type != TokenType::OpenCurlyBracket { return None; } - reader.consume(TokenType::OpenCurlyBracket, log); + let start = reader.consume(TokenType::OpenCurlyBracket, log).span.start; let mut children = Vec::new(); loop { if reader.peek().token_type == TokenType::CloseCurlyBracket { @@ -992,9 +1127,15 @@ fn parse_statblock( // FIXME: Log error break; } - reader.consume(TokenType::CloseCurlyBracket, log); - Some(Box::new(ParsedStatement::StatBlock { - statements: children, + let last = reader.consume(TokenType::CloseCurlyBracket, log); + Some(Box::new(ParsedStatement { + data: ParsedStatementData::StatBlock { + statements: children, + }, + span: Span { + start, + end: last.span.end, + }, })) } @@ -1006,6 +1147,7 @@ fn parse_var( // var ::= ['private'|'protected'] type identifier + let start = outer_reader.peek().span.start; let mut reader = outer_reader.create_inner(); let mut field_mod: BitFlags = BitFlags::empty(); let property_type: Option>; @@ -1057,14 +1199,17 @@ fn parse_var( if reader.peek().token_type != TokenType::Semicolon { return None; } - reader.next(); + let end = reader.next().span.end; outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::Var { - modifier: field_mod, - var_type: property_type.unwrap(), - identifier: identifier.unwrap(), - assignment, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Var { + modifier: field_mod, + var_type: property_type.unwrap(), + identifier: identifier.unwrap(), + assignment, + }, + span: Span { start, end }, })) } @@ -1093,7 +1238,7 @@ fn parse_switch( log: &mut dyn FnMut(Message, Span), ) -> Option> { // switch ::= 'switch' '(' assign ')' '{' {case} '}'; - reader.consume(TokenType::SwitchKeyword, log); + let start = reader.consume(TokenType::SwitchKeyword, log).span.start; reader.consume(TokenType::OpenBracket, log); let assign = parse_assign(reader, log); // FIXME: Deal with None assign @@ -1114,10 +1259,13 @@ fn parse_switch( } vec.push(case.unwrap()); } - reader.consume(TokenType::CloseCurlyBracket, log); - Some(Box::new(ParsedStatement::Switch { - expression: assign.unwrap(), - cases: vec, + let end = reader.consume(TokenType::CloseCurlyBracket, log).span.end; + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Switch { + expression: assign.unwrap(), + cases: vec, + }, + span: Span { start, end }, })) } @@ -1127,7 +1275,9 @@ fn parse_case( ) -> Option> { // case ::= (('case' expr) | 'default') ':' {statement}; let mut expression = None; - let initial_token = &reader.peek().token_type; + let initial = &reader.peek(); + let initial_token = &initial.token_type; + let initial_span = initial.span; if initial_token == &TokenType::DefaultKeyword { reader.next(); } else if initial_token == &TokenType::CaseKeyword { @@ -1140,9 +1290,20 @@ fn parse_case( reader.consume(TokenType::Colon, log); let statement = parse_statement(reader, log); // FIXME: deal with None statement - Some(Box::new(ParsedStatement::Case { - expression, - statement: statement.unwrap(), + + let mut end = initial_span.start; + if let Some(s) = &statement { + end = s.span.end; + } + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Case { + expression, + statement: statement.unwrap(), + }, + span: Span { + start: initial_span.start, + end, + }, })) } @@ -1151,14 +1312,21 @@ fn parse_try( log: &mut dyn FnMut(Message, Span), ) -> Option> { // try ::= 'try' statblock 'catch' statblock; - reader.consume(TokenType::TryKeyword, log); + let start = reader.consume(TokenType::TryKeyword, log).span.start; let try_block = parse_statblock(reader, log); reader.consume(TokenType::CatchKeyword, log); let catch_block = parse_statblock(reader, log); + let mut end = start; + if let Some(s) = &catch_block { + end = s.span.end; + } // FIXME: Deal with empty try or catch blocks. - Some(Box::new(ParsedStatement::TryStatement { - try_block: try_block.unwrap(), - catch_block: catch_block.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::TryStatement { + try_block: try_block.unwrap(), + catch_block: catch_block.unwrap(), + }, + span: Span { start, end }, })) } @@ -1167,18 +1335,21 @@ fn parse_dowhile( log: &mut dyn FnMut(Message, Span), ) -> Option> { // dowhile ::= 'do' statement 'while' '(' assign ')' ';'; - reader.consume(TokenType::DoKeyword, log); + let start = reader.consume(TokenType::DoKeyword, log).span.start; let statement = parse_statement(reader, log); reader.consume(TokenType::WhileKeyword, log); reader.consume(TokenType::OpenBracket, log); let condition = parse_assign(reader, log); reader.consume(TokenType::CloseBracket, log); - reader.consume(TokenType::Semicolon, log); + let end = reader.consume(TokenType::Semicolon, log).span.end; // FIXME: Deal with empty statement or condition. - Some(Box::new(ParsedStatement::DoWhileStatement { - statement: statement.unwrap(), - condition: condition.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::DoWhileStatement { + statement: statement.unwrap(), + condition: condition.unwrap(), + }, + span: Span { start, end }, })) } @@ -1187,16 +1358,23 @@ fn parse_while( log: &mut dyn FnMut(Message, Span), ) -> Option> { // while ::= 'while' '(' assign ')' statement; - reader.consume(TokenType::WhileKeyword, log); + let start = reader.consume(TokenType::WhileKeyword, log).span.start; reader.consume(TokenType::OpenBracket, log); let condition = parse_assign(reader, log); reader.consume(TokenType::CloseBracket, log); let statement = parse_statement(reader, log); + let mut end = start; + if let Some(s) = &statement { + end = s.span.end; + } // FIXME: Deal with empty statement or condition. - Some(Box::new(ParsedStatement::WhileStatement { - condition: condition.unwrap(), - statement: statement.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::WhileStatement { + condition: condition.unwrap(), + statement: statement.unwrap(), + }, + span: Span { start, end }, })) } @@ -1205,7 +1383,7 @@ fn parse_for( log: &mut dyn FnMut(Message, Span), ) -> Option> { // for ::= 'for' '(' (var | exprstat) exprstat [assign {',' assign}] ')' statement; - reader.consume(TokenType::ForKeyword, log); + let start = reader.consume(TokenType::ForKeyword, log).span.start; reader.consume(TokenType::OpenBracket, log); let mut initializer = parse_var(reader, log); if initializer.is_none() { @@ -1232,11 +1410,14 @@ fn parse_for( } reader.next(); } - reader.consume(TokenType::CloseBracket, log); - Some(Box::new(ParsedStatement::ForStatement { - initializer: initializer.unwrap(), - bounds: bounds.unwrap(), - increment: increment_expressions, + let end = reader.consume(TokenType::CloseBracket, log).span.end; + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ForStatement { + initializer: initializer.unwrap(), + bounds: bounds.unwrap(), + increment: increment_expressions, + }, + span: Span { start, end }, })) } @@ -1245,23 +1426,35 @@ fn parse_if( log: &mut dyn FnMut(Message, Span), ) -> Option> { // if ::= 'if' '(' assign ')' statement ['else' statement]; - reader.consume(TokenType::IfKeyword, log); + let start = reader.consume(TokenType::IfKeyword, log).span.start; reader.consume(TokenType::OpenBracket, log); let condition = parse_assign(reader, log); // FIXME: deal with empty condition reader.consume(TokenType::CloseBracket, log); let statement = parse_statement(reader, log); + let mut end = start; + if let Some(s) = &statement { + end = s.span.end; + } + let mut else_statement = None; if reader.peek().token_type == TokenType::ElseKeyword { reader.next(); else_statement = parse_statement(reader, log); + end = start; + if let Some(s) = &else_statement { + end = s.span.end; + } } - Some(Box::new(ParsedStatement::IfStatement { - condition: condition.unwrap(), - statement: statement.unwrap(), - else_statement, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::IfStatement { + condition: condition.unwrap(), + statement: statement.unwrap(), + else_statement, + }, + span: Span { start, end }, })) } @@ -1270,9 +1463,12 @@ fn parse_break( log: &mut dyn FnMut(Message, Span), ) -> Option> { // break ::= 'break' ';'; - reader.consume(TokenType::BreakKeyword, log); - reader.consume(TokenType::Semicolon, log); - Some(Box::new(ParsedStatement::BreakStatement {})) + let start = reader.consume(TokenType::BreakKeyword, log).span.start; + let end = reader.consume(TokenType::Semicolon, log).span.end; + Some(Box::new(ParsedStatement { + data: ParsedStatementData::BreakStatement, + span: Span { start, end }, + })) } fn parse_continue( @@ -1280,9 +1476,12 @@ fn parse_continue( log: &mut dyn FnMut(Message, Span), ) -> Option> { // continue ::= 'continue' ';'; - reader.consume(TokenType::ContinueKeyword, log); - reader.consume(TokenType::Semicolon, log); - Some(Box::new(ParsedStatement::ContinueStatement {})) + let start = reader.consume(TokenType::ContinueKeyword, log).span.start; + let end = reader.consume(TokenType::Semicolon, log).span.end; + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ContinueStatement, + span: Span { start, end }, + })) } fn parse_exprstat( @@ -1301,10 +1500,13 @@ fn parse_return( log: &mut dyn FnMut(Message, Span), ) -> Option> { // return ::= 'return' [assign] ';'; - reader.consume(TokenType::ReturnKeyword, log); + let start = reader.consume(TokenType::ReturnKeyword, log).span.start; let expression = parse_assign(reader, log); - reader.consume(TokenType::Semicolon, log); - Some(Box::new(ParsedStatement::ReturnStatement { expression })) + let end = reader.consume(TokenType::Semicolon, log).span.end; + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ReturnStatement { expression }, + span: Span { start, end }, + })) } fn parse_ternary( @@ -1321,11 +1523,24 @@ fn parse_ternary( reader.consume(TokenType::Colon, log); let b = parse_assign(reader, log); // FIXME: Deal with None a or b - return Some(Box::new(ParsedStatement::TernaryExpr { - left: expr.unwrap(), - operator: TernaryOperator::Conditional, - middle: a.unwrap(), - right: b.unwrap(), + + let mut start = 0; + let mut end = 0; + if let Some(s) = &expr { + start = s.span.start; + } + if let Some(s) = &b { + end = s.span.end; + } + + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::TernaryExpr { + left: expr.unwrap(), + operator: TernaryOperator::Conditional, + middle: a.unwrap(), + right: b.unwrap(), + }, + span: Span { start, end }, })); } expr @@ -1354,12 +1569,26 @@ fn parse_expr( if let Some(..) = binary_operand { let expr_term2 = parse_exprterm(reader, log); if expr_term2.is_none() { - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { + start: expr_term.unwrap().span.start, + end: reader.peek().span.end, + }, + })); } - return Some(Box::new(ParsedStatement::BinaryExpr { - left: expr_term.unwrap(), - operator: binary_operand.unwrap(), - right: expr_term2.unwrap(), + let left = expr_term.unwrap(); + let right = expr_term2.unwrap(); + let start = left.span.start; + let end = right.span.end; + + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::BinaryExpr { + left, + operator: binary_operand.unwrap(), + right, + }, + span: Span { start, end }, })); } @@ -1371,6 +1600,7 @@ fn parse_exprterm( log: &mut dyn FnMut(Message, Span), ) -> Option> { let mut reader = outer_reader.create_inner(); + let start = reader.peek().span.start; // exprterm ::= ([type '='] initlist) | ({exprpreop} exprvalue {exprpostop}); let expr_type = parse_type(&mut reader, log); if expr_type.is_some() && reader.peek().token_type == TokenType::Equals { @@ -1384,9 +1614,13 @@ fn parse_exprterm( if let Some(initlist) = init_list { outer_reader.set_from_inner(&reader); - return Some(Box::new(ParsedStatement::ExprTermInitList { - statement_type: expr_type, - initlist, + let end = initlist.span.end; + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::ExprTermInitList { + statement_type: expr_type, + initlist, + }, + span: Span { start, end }, })); } @@ -1410,9 +1644,13 @@ fn parse_exprterm( } for op in expr_pre_op.iter().rev() { - real_value = Box::new(ParsedStatement::ExprPreOp { - operator: *op, - operand: real_value, + let end = real_value.span.end; + real_value = Box::new(ParsedStatement { + data: ParsedStatementData::ExprPreOp { + operator: *op, + operand: real_value, + }, + span: Span { start, end }, }) } @@ -1429,21 +1667,29 @@ fn parse_exprpostop( // ('.' (funccall | identifier)) if reader.peek().token_type == TokenType::Dot { - reader.next(); + let start = reader.next().span.start; if let Some(s) = parse_funccall(reader, log) { + let end = s.span.end; return ( - Box::new(ParsedStatement::MemberFuncCall { - operand: base, - func_call: s, + Box::new(ParsedStatement { + data: ParsedStatementData::MemberFuncCall { + operand: base, + func_call: s, + }, + span: Span { start, end }, }), true, ); } if let Some(s) = parse_identifier(reader, log, false) { + let end = reader.peek().span.end; return ( - Box::new(ParsedStatement::MemberAccess { - operand: base, - identifier: s, + Box::new(ParsedStatement { + data: ParsedStatementData::MemberAccess { + operand: base, + identifier: s, + }, + span: Span { start, end }, }), true, ); @@ -1480,11 +1726,15 @@ fn parse_exprpostop( log(Message::EmptyIndex, reader.peek().span); } reader.set_from_inner(&inner_reader); - reader.consume(TokenType::CloseBlockBracket, log); + let start = base.span.start; + let end = reader.consume(TokenType::CloseBlockBracket, log).span.end; return ( - Box::new(IndexingOperator { - operand: base, - index: vec, + Box::new(ParsedStatement { + data: ParsedStatementData::IndexingOperator { + operand: base, + index: vec, + }, + span: Span { start, end }, }), true, ); @@ -1495,10 +1745,14 @@ fn parse_exprpostop( // call if reader.peek().token_type == TokenType::OpenBracket { if let Some(s) = parse_arglist(reader, log) { + let span = s.span; return ( - Box::new(AnonymousCall { - operand: base, - arg_list: s, + Box::new(ParsedStatement { + data: ParsedStatementData::AnonymousCall { + operand: base, + arg_list: s, + }, + span, }), true, ); @@ -1507,11 +1761,15 @@ fn parse_exprpostop( // '++' if reader.peek().token_type == TokenType::PlusPlus { - reader.next(); + let start = base.span.start; + let end = reader.next().span.end; return ( - Box::new(ExprPostOp { - operand: base, - operator: PostOperator::Increment, + Box::new(ParsedStatement { + data: ParsedStatementData::ExprPostOp { + operand: base, + operator: PostOperator::Increment, + }, + span: Span { start, end }, }), true, ); @@ -1519,11 +1777,15 @@ fn parse_exprpostop( // '--' if reader.peek().token_type == TokenType::MinusMinus { - reader.next(); + let start = base.span.start; + let end = reader.next().span.end; return ( - Box::new(ExprPostOp { - operand: base, - operator: PostOperator::Decrement, + Box::new(ParsedStatement { + data: ParsedStatementData::ExprPostOp { + operand: base, + operator: PostOperator::Decrement, + }, + span: Span { start, end }, }), true, ); @@ -1538,8 +1800,11 @@ fn parse_exprvalue( ) -> Option> { // exprvalue ::= 'void' | constructcall | funccall | varaccess | cast | literal | '(' assign ')' | lambda; if outer_reader.peek().token_type == TokenType::VoidKeyword { - outer_reader.next(); - return Some(Box::new(ParsedStatement::ExprVoidValue {})); + let span = outer_reader.next().span; + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::ExprVoidValue {}, + span, + })); } let mut reader = outer_reader.create_inner(); if let Some(s) = parse_constructcall(&mut reader, log) { @@ -1625,15 +1890,29 @@ fn parse_literal( reader: &mut ParseReader, _log: &mut dyn FnMut(Message, Span), ) -> Option> { - let value = match &reader.peek().token_type { - TokenType::IntegerLiteral(v) => Some(Box::new(ParsedStatement::IntegerLiteral(*v))), - TokenType::FloatLiteral(v) => Some(Box::new(ParsedStatement::FloatLiteral(*v))), - TokenType::TrueKeyword => Some(Box::new(ParsedStatement::BoolLiteral(true))), - TokenType::FalseKeyword => Some(Box::new(ParsedStatement::BoolLiteral(false))), - // FIXME: String copy, too slow. - TokenType::StringLiteral(v) => { - Some(Box::new(ParsedStatement::StringLiteral(v.to_string()))) - } + let token = reader.peek(); + let value = match &token.token_type { + TokenType::IntegerLiteral(v) => Some(Box::new(ParsedStatement { + data: ParsedStatementData::IntegerLiteral(*v), + span: token.span, + })), + TokenType::FloatLiteral(v) => Some(Box::new(ParsedStatement { + data: ParsedStatementData::FloatLiteral(*v), + span: token.span, + })), + TokenType::TrueKeyword => Some(Box::new(ParsedStatement { + data: ParsedStatementData::BoolLiteral(true), + span: token.span, + })), + TokenType::FalseKeyword => Some(Box::new(ParsedStatement { + data: ParsedStatementData::BoolLiteral(false), + span: token.span, + })), + // TODO: String copy, might be able to do faster. + TokenType::StringLiteral(v) => Some(Box::new(ParsedStatement { + data: ParsedStatementData::StringLiteral(v.to_string()), + span: token.span, + })), _ => None, }; if value.is_some() { @@ -1650,7 +1929,7 @@ fn parse_cast( if reader.peek().token_type != TokenType::CastKeyword { return None; } - reader.next(); + let start = reader.next().span.start; reader.consume(TokenType::LessThan, log); let cast_type = parse_type(reader, log); // FIXME: deal with no cast type @@ -1658,11 +1937,14 @@ fn parse_cast( reader.consume(TokenType::OpenBracket, log); let assign = parse_assign(reader, log); // FIXME: deal with no assign - reader.consume(TokenType::CloseBracket, log); + let end = reader.consume(TokenType::CloseBracket, log).span.end; - Some(Box::new(ParsedStatement::Cast { - cast_type: cast_type.unwrap(), - assign: assign.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Cast { + cast_type: cast_type.unwrap(), + assign: assign.unwrap(), + }, + span: Span { start, end }, })) } @@ -1673,12 +1955,21 @@ fn parse_varaccess( // scope identifier let mut reader = outer_reader.create_inner(); let scope = parse_scope(&mut reader, log); + let mut span = reader.peek().span; let identifier = parse_identifier(&mut reader, log, true); identifier.as_ref()?; outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::VarAccess { - scope, - identifier: identifier.unwrap(), + + if let Some(s) = &scope { + span.start = s.span.start; + } + + Some(Box::new(ParsedStatement { + data: ParsedStatementData::VarAccess { + scope, + identifier: identifier.unwrap(), + }, + span, })) } @@ -1694,9 +1985,18 @@ fn parse_constructcall( arg_list.as_ref()?; outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::ConstructCall { - statement_type: construct_type, - arglist: arg_list.unwrap(), + + let statement_type = construct_type.unwrap(); + let arglist = arg_list.unwrap(); + + let start = statement_type.span.start; + let end = arglist.span.end; + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ConstructCall { + statement_type, + arglist, + }, + span: Span { start, end }, })) } @@ -1706,6 +2006,7 @@ fn parse_funccall( ) -> Option> { // scope identifier arglist let mut reader = outer_reader.create_inner(); + let start = reader.peek().span.start; let scope = parse_scope(&mut reader, log); let identifier = parse_identifier(&mut reader, log, true); identifier.as_ref()?; @@ -1713,11 +2014,17 @@ fn parse_funccall( let arg_list = parse_arglist(&mut reader, log); arg_list.as_ref()?; + let arglist = arg_list.unwrap(); + let end = arglist.span.end; + outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::FuncCall { - scope, - identifier: identifier.unwrap(), - arglist: arg_list.unwrap(), + Some(Box::new(ParsedStatement { + data: ParsedStatementData::FuncCall { + scope, + identifier: identifier.unwrap(), + arglist, + }, + span: Span { start, end }, })) } @@ -1729,7 +2036,7 @@ fn parse_arglist( if reader.peek().token_type != TokenType::OpenBracket { return None; } - reader.next(); + let start = reader.next().span.start; let mut args = Vec::new(); loop { if reader.peek().token_type == TokenType::CloseBracket @@ -1744,16 +2051,23 @@ fn parse_arglist( inner_reader.next(); reader.set_from_inner(&inner_reader); } - let mut expression = parse_assign(reader, log); + let expression = parse_assign(reader, log); if expression.is_none() { // FIXME: logging - expression = Some(Box::new(ParsedStatement::Invalid {})); + let end = reader.peek().span.end; + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { start, end }, + })); } args.push((identifier, expression.unwrap())); } - reader.consume(TokenType::CloseBracket, log); + let end = reader.consume(TokenType::CloseBracket, log).span.end; - Some(Box::new(ParsedStatement::ArgList { args })) + Some(Box::new(ParsedStatement { + data: ParsedStatementData::ArgList { args }, + span: Span { start, end }, + })) } fn parse_exprpreop( @@ -1797,13 +2111,27 @@ fn parse_assign( if let Some(assign_op) = parse_assignop(reader, log) { let assign = parse_assign(reader, log); if assign.is_none() { + let start = ternary.unwrap().span.start; + let end = reader.peek().span.end; // FIXME: Logging - return Some(Box::new(ParsedStatement::Invalid)); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Invalid, + span: Span { start, end }, + })); } - return Some(Box::new(ParsedStatement::Assignment { - left: ternary.unwrap(), - operator: assign_op, - right: assign.unwrap(), + + let left = ternary.unwrap(); + let right = assign.unwrap(); + + let start = left.span.start; + let end = right.span.end; + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::Assignment { + left, + operator: assign_op, + right, + }, + span: Span { start, end }, })); } ternary @@ -1816,6 +2144,7 @@ fn parse_type( // type ::= ['const'] scope datatype ['<' type {',' type} '>'] { ('[' ']') | ('@' ['const']) }; let f = reader.peek(); + let start = f.span.start; let mut is_const = false; if f.token_type == TokenType::ConstKeyword { reader.next(); @@ -1828,18 +2157,20 @@ fn parse_type( // TODO: Generics let mut modifiers: Vec = Vec::new(); + let datatype = datatype.unwrap(); + let mut end = datatype.span.end; loop { let n = reader.peek(); match n.token_type { TokenType::OpenBlockBracket => { reader.next(); - reader.consume(TokenType::CloseBlockBracket, log); + end = reader.consume(TokenType::CloseBlockBracket, log).span.end; modifiers.push(ParsedTypeModifier::Array); } TokenType::AtSymbol => { - reader.next(); + end = reader.next().span.end; if reader.peek().token_type == TokenType::ConstKeyword { - reader.next(); + end = reader.next().span.end; modifiers.push(ParsedTypeModifier::ConstHandle); } else { modifiers.push(ParsedTypeModifier::Handle); @@ -1849,11 +2180,14 @@ fn parse_type( } } - Some(Box::new(ParsedStatement::Type { - is_const, - scope, - datatype: datatype.unwrap(), - modifiers, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Type { + is_const, + scope, + datatype, + modifiers, + }, + span: Span { start, end }, })) } @@ -1863,18 +2197,20 @@ fn parse_scope( ) -> Option> { // scope ::= ['::'] {identifier '::'} [identifier ['<' type {',' type} '>'] '::'] let mut reader = outer_reader.create_inner(); + let start = reader.peek().span.start; let is_global = reader.peek().token_type == TokenType::ColonColon; if is_global { reader.next(); } let mut scope: Vec = Vec::new(); + let mut end = reader.peek().span.end; loop { let n = reader.peek(); if let TokenType::Identifier(s) = &n.token_type { let identifier = s.to_string(); if reader.peek().token_type == TokenType::ColonColon { reader.next(); - reader.next(); + end = reader.next().span.end; scope.push(identifier); } else { break; @@ -1888,10 +2224,13 @@ fn parse_scope( None } else { outer_reader.set_from_inner(&reader); - Some(Box::new(ParsedStatement::Scope { - is_global, - scope, - generic_types: None, + Some(Box::new(ParsedStatement { + data: ParsedStatementData::Scope { + is_global, + scope, + generic_types: None, + }, + span: Span { start, end }, })) } } @@ -1900,12 +2239,19 @@ fn parse_datatype( reader: &mut ParseReader, log: &mut dyn FnMut(Message, Span), ) -> Option> { + let span = reader.peek().span; if let Some(identifier) = parse_identifier(reader, log, true) { - return Some(Box::new(ParsedStatement::DataTypeIdentifier { identifier })); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::DataTypeIdentifier { identifier }, + span, + })); } if reader.peek().token_type == TokenType::AutoKeyword { reader.next(); - return Some(Box::new(ParsedStatement::DataTypeAuto {})); + return Some(Box::new(ParsedStatement { + data: ParsedStatementData::DataTypeAuto, + span, + })); } parse_primtype(reader, log) } @@ -1916,54 +2262,57 @@ fn parse_primtype( ) -> Option> { let key = reader.peek(); let res = match &key.token_type { - TokenType::VoidKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { + TokenType::VoidKeyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Void, - })), - TokenType::Int8Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Int8Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Int8, - })), - TokenType::Int16Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Int16Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Int16, - })), - TokenType::Int32Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Int32Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Int32, - })), - TokenType::IntKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::IntKeyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Int32, - })), - TokenType::Int64Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Int64Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Int64, - })), - TokenType::Uint8Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Uint8Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::UInt8, - })), - TokenType::Uint16Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Uint16Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::UInt16, - })), - TokenType::Uint32Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Uint32Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::UInt32, - })), - TokenType::UintKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::UintKeyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::UInt32, - })), - TokenType::Uint64Keyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::Uint64Keyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::UInt64, - })), - TokenType::FloatKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::FloatKeyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Float, - })), - TokenType::DoubleKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::DoubleKeyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Double, - })), - TokenType::BoolKeyword => Some(Box::new(ParsedStatement::DataTypePrimType { + }), + TokenType::BoolKeyword => Some(ParsedStatementData::DataTypePrimType { prim_type: PrimitiveType::Bool, - })), + }), _ => None, }; - if res.is_some() { + if let Some(data) = res { + let span = key.span; reader.next(); + Some(Box::new(ParsedStatement { data, span })) + } else { + None } - res } fn parse_bitop( diff --git a/src/parsing/parser/parsed_statement.rs b/src/parsing/parser/parsed_statement.rs index 3067622..185cb13 100644 --- a/src/parsing/parser/parsed_statement.rs +++ b/src/parsing/parser/parsed_statement.rs @@ -9,6 +9,7 @@ use crate::parsing::parser::parser_operators::{ use crate::prim_type::PrimitiveType; use enumflags2::BitFlags; +use crate::span::Span; #[cfg(test)] use serde_derive::{Deserialize, Serialize}; @@ -23,10 +24,17 @@ pub struct ParsedParameter { #[derive(PartialEq, Debug)] #[cfg_attr(test, derive(Serialize, Deserialize))] -pub enum ParsedStatement { +pub struct ParsedStatement { + pub data: ParsedStatementData, + pub span: Span, +} + +#[derive(PartialEq, Debug)] +#[cfg_attr(test, derive(Serialize, Deserialize))] +pub enum ParsedStatementData { Invalid, Script { - statements: Vec, + statements: Vec>, }, Namespace { identifier: String, @@ -36,12 +44,12 @@ pub enum ParsedStatement { type_mod: BitFlags, identifier: String, inherits: Vec, - statements: Vec, + statements: Vec>, }, Scope { is_global: bool, scope: Vec, - generic_types: Option>, + generic_types: Option>>, }, VirtProp { field_mod: Option, @@ -60,7 +68,7 @@ pub enum ParsedStatement { DataTypeIdentifier { identifier: String, }, - DataTypeAuto {}, + DataTypeAuto, DataTypePrimType { prim_type: PrimitiveType, }, @@ -90,7 +98,7 @@ pub enum ParsedStatement { }, ExprVoidValue {}, ConstructCall { - statement_type: Option>, + statement_type: Box, arglist: Box, }, FuncCall { @@ -176,8 +184,8 @@ pub enum ParsedStatement { statement: Box, else_statement: Option>, }, - BreakStatement {}, - ContinueStatement {}, + BreakStatement, + ContinueStatement, ReturnStatement { expression: Option>, }, diff --git a/src/parsing/parser/parser_tests.rs b/src/parsing/parser/parser_tests.rs index 6bc6f04..1019522 100644 --- a/src/parsing/parser/parser_tests.rs +++ b/src/parsing/parser/parser_tests.rs @@ -1,8 +1,9 @@ use super::parse; use super::parsed_statement::ParsedStatement; use crate::modifiers::TypeModifier; +use crate::parsing::lexer::lex_tokens::TokenType::AutoKeyword; use crate::parsing::lexer::lex_tokens::{LexToken, TokenType}; -use crate::parsing::parser::parsed_statement::ParsedStatement::DataTypeAuto; +use crate::parsing::parser::parsed_statement::ParsedStatementData; use crate::parsing::parser::parser_operators::{BinaryOperator, PreOperator}; use crate::span::Span; @@ -33,11 +34,12 @@ fn test_empty_namespace() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Namespace { identifier, script } = &statements[0] { + if let ParsedStatementData::Namespace { identifier, script } = &statements[0].as_ref().data + { assert_eq!(identifier, "foo"); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(0, statements.len()); } else { unreachable!(); @@ -66,14 +68,14 @@ fn test_empty_interface() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Interface { + if let ParsedStatementData::Interface { type_mod, identifier, inherits, statements, - } = &statements[0] + } = &statements[0].as_ref().data { assert!(type_mod.is_empty()); assert_eq!(identifier, "foo"); @@ -105,14 +107,14 @@ fn test_empty_external_shared_interface() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Interface { + if let ParsedStatementData::Interface { type_mod, identifier, inherits, statements, - } = &statements[0] + } = &statements[0].as_ref().data { assert!(!type_mod.is_empty()); assert!(type_mod.contains(TypeModifier::External)); @@ -152,20 +154,20 @@ fn test_interface_with_virtprop() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Interface { + if let ParsedStatementData::Interface { type_mod, identifier, inherits, statements, - } = &statements[0] + } = &statements[0].as_ref().data { assert!(type_mod.is_empty()); assert_eq!(identifier, "foo"); assert_eq!(inherits.len(), 0); assert_eq!(statements.len(), 1); - if let ParsedStatement::VirtProp { + if let ParsedStatementData::VirtProp { field_mod, property_type, identifier, @@ -176,16 +178,16 @@ fn test_interface_with_virtprop() { has_set, is_set_const, set_statement, - } = &statements[0] + } = &statements[0].as_ref().data { assert_eq!(*field_mod, None); - if let ParsedStatement::Type { + if let ParsedStatementData::Type { is_const, datatype, .. - } = property_type.as_ref() + } = &property_type.as_ref().data { assert!(!is_const); - if let ParsedStatement::DataTypeIdentifier { identifier, .. } = - datatype.as_ref() + if let ParsedStatementData::DataTypeIdentifier { identifier, .. } = + &datatype.as_ref().data { assert_eq!(identifier, "bar"); } else { @@ -231,30 +233,33 @@ fn test_assign_to_global_variable() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Var { + if let ParsedStatementData::Var { modifier, var_type, identifier, assignment, - } = &statements[0] + } = &statements[0].as_ref().data { assert!(modifier.is_empty()); assert_eq!( - *var_type.as_ref(), - ParsedStatement::Type { + var_type.as_ref().data, + ParsedStatementData::Type { is_const: false, scope: None, - datatype: Box::from(DataTypeAuto {}), + datatype: Box::from(ParsedStatement { + data: ParsedStatementData::DataTypeAuto, + span: Span { start: 0, end: 0 } + }), modifiers: vec![] } ); assert_eq!(identifier, "foo"); assert!(assignment.is_some()); assert_eq!( - *(assignment.as_ref().unwrap().as_ref()), - ParsedStatement::IntegerLiteral(100) + (assignment.as_ref().unwrap().as_ref()).data, + ParsedStatementData::IntegerLiteral(100) ); } else { unreachable!() @@ -283,32 +288,38 @@ fn test_assign_negative_to_global_variable() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Var { + if let ParsedStatementData::Var { modifier, var_type, identifier, assignment, - } = &statements[0] + } = &statements[0].as_ref().data { assert!(modifier.is_empty()); assert_eq!( - *var_type.as_ref(), - ParsedStatement::Type { + var_type.as_ref().data, + ParsedStatementData::Type { is_const: false, scope: None, - datatype: Box::from(DataTypeAuto {}), + datatype: Box::from(ParsedStatement { + data: ParsedStatementData::DataTypeAuto, + span: Span { start: 0, end: 0 } + }), modifiers: vec![] } ); assert_eq!(identifier, "foo"); assert!(assignment.is_some()); assert_eq!( - *(assignment.as_ref().unwrap().as_ref()), - ParsedStatement::ExprPreOp { + (assignment.as_ref().unwrap().as_ref()).data, + ParsedStatementData::ExprPreOp { operator: PreOperator::Negative, - operand: Box::from(ParsedStatement::IntegerLiteral(100)), + operand: Box::from(ParsedStatement { + data: ParsedStatementData::IntegerLiteral(100), + span: Span { start: 0, end: 0 } + }), } ); } else { @@ -340,35 +351,47 @@ fn test_assign_addition_to_global_variable() { std::panic::panic_any(_message.stringify()); }, ); - if let ParsedStatement::Script { statements } = script.as_ref() { + if let ParsedStatementData::Script { statements } = &script.as_ref().data { assert_eq!(1, statements.len()); - if let ParsedStatement::Var { + if let ParsedStatementData::Var { modifier, var_type, identifier, assignment, - } = &statements[0] + } = &statements[0].as_ref().data { assert!(modifier.is_empty()); assert_eq!( - *var_type.as_ref(), - ParsedStatement::Type { + var_type.as_ref().data, + ParsedStatementData::Type { is_const: false, scope: None, - datatype: Box::from(DataTypeAuto {}), + datatype: Box::from(ParsedStatement { + data: ParsedStatementData::DataTypeAuto, + span: Span { start: 0, end: 0 } + }), modifiers: vec![] } ); assert_eq!(identifier, "foo"); assert!(assignment.is_some()); assert_eq!( - *(assignment.as_ref().unwrap().as_ref()), - ParsedStatement::BinaryExpr { - left: Box::new(ParsedStatement::IntegerLiteral(100)), + (assignment.as_ref().unwrap().as_ref()).data, + ParsedStatementData::BinaryExpr { + left: Box::new(ParsedStatement { + data: ParsedStatementData::IntegerLiteral(100), + span: Span { start: 0, end: 0 } + }), operator: BinaryOperator::Addition, - right: Box::new(ParsedStatement::ExprPreOp { - operator: PreOperator::Negative, - operand: Box::new(ParsedStatement::IntegerLiteral(20)), + right: Box::new(ParsedStatement { + data: ParsedStatementData::ExprPreOp { + operator: PreOperator::Negative, + operand: Box::new(ParsedStatement { + data: ParsedStatementData::IntegerLiteral(20), + span: Span { start: 0, end: 0 } + }), + }, + span: Span { start: 0, end: 0 } }), } ); diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..a1a23c2 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,10 @@ +use crate::defines::PointerSize; + +pub mod script_type; +pub mod script_type_namespace; +pub mod type_library; + +pub trait Type { + fn get_size(&self) -> PointerSize; + fn is_enum(&self) -> bool; +} diff --git a/src/types/script_type.rs b/src/types/script_type.rs new file mode 100644 index 0000000..95ec8bd --- /dev/null +++ b/src/types/script_type.rs @@ -0,0 +1,33 @@ +use crate::defines::PointerSize; +use crate::types::Type; +use std::sync::Arc; + +pub struct ScriptType { + fields: Vec, + size: PointerSize, + is_enum: bool, +} + +pub struct ScriptTypeField { + field_type: Arc, +} + +impl ScriptType { + pub fn new() -> ScriptType { + ScriptType { + fields: Vec::new(), + size: 0, + is_enum: false, + } + } +} + +impl Type for ScriptType { + fn get_size(&self) -> PointerSize { + self.size + } + + fn is_enum(&self) -> bool { + self.is_enum + } +} diff --git a/src/types/script_type_namespace.rs b/src/types/script_type_namespace.rs new file mode 100644 index 0000000..31ef51c --- /dev/null +++ b/src/types/script_type_namespace.rs @@ -0,0 +1,22 @@ +use crate::types::script_type::ScriptType; +use std::collections::HashMap; + +pub struct ScriptTypeNamespace { + types: HashMap, + namespaces: HashMap>, + root_namespace: Option>, +} + +impl ScriptTypeNamespace { + pub fn new<'b>(root: Option>) -> ScriptTypeNamespace { + ScriptTypeNamespace { + types: HashMap::new(), + namespaces: HashMap::new(), + root_namespace: root, + } + } + + pub fn register(&mut self, identifier: &String, script_type: ScriptType) { + self.types.insert(identifier.to_string(), script_type); + } +} diff --git a/src/types/type_library.rs b/src/types/type_library.rs new file mode 100644 index 0000000..0da79f8 --- /dev/null +++ b/src/types/type_library.rs @@ -0,0 +1,22 @@ +use crate::types::script_type_namespace::ScriptTypeNamespace; +use std::borrow::{Borrow, BorrowMut}; + +pub struct TypeLibrary { + script_types: Box, +} + +impl TypeLibrary { + pub fn new() -> TypeLibrary { + TypeLibrary { + script_types: Box::new(ScriptTypeNamespace::new(None)), + } + } + + pub fn get_global_namespace(&self) -> &ScriptTypeNamespace { + self.script_types.borrow() + } + + pub fn get_global_namespace_mut(&mut self) -> &mut ScriptTypeNamespace { + self.script_types.borrow_mut() + } +}