From 2cc2a5322d4d09778c973928d2ce859cc3721ab8 Mon Sep 17 00:00:00 2001 From: Stepami Date: Mon, 16 Oct 2023 22:32:48 +0300 Subject: [PATCH] guard against no initializer --- Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs | 8 +++++++- .../AfterTypesAreLoaded/LexicalDeclaration.cs | 8 ++++---- .../Exceptions/ConstWithoutInitializer.cs | 11 ----------- .../Exceptions/DeclarationWithoutInitializer.cs | 11 +++++++++++ .../IR/CheckSemantics/Visitors/DeclarationVisitor.cs | 11 +++++++++-- 5 files changed, 31 insertions(+), 18 deletions(-) delete mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs create mode 100644 Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationWithoutInitializer.cs diff --git a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs b/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs index e7f21c24..a5e0e519 100644 --- a/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs +++ b/Interpreter.Lib/FrontEnd/TopDownParse/Impl/Parser.cs @@ -368,7 +368,13 @@ private void AddToDeclaration(LexicalDeclaration declaration) { var ident = Expect("Ident"); var identRef = new IdentifierReference(ident.Value) { Segment = ident.Segment }; - AssignmentExpression assignment = null; + var assignment = new AssignmentExpression( + new MemberExpression(identRef), + new ImplicitLiteral( + new TypeIdentValue( + new IdentifierReference("undefined")))) + { Segment = ident.Segment }; + if (CurrentIs("Assign")) { var assignSegment = Expect("Assign").Segment; diff --git a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs index 775659e1..008d690c 100644 --- a/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs +++ b/Interpreter.Lib/IR/Ast/Impl/Nodes/Declarations/AfterTypesAreLoaded/LexicalDeclaration.cs @@ -8,12 +8,12 @@ namespace Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; public class LexicalDeclaration : AfterTypesAreLoadedDeclaration { - public bool Readonly { get; } + public bool ReadOnly { get; } public List Assignments { get; } - public LexicalDeclaration(bool @readonly) + public LexicalDeclaration(bool readOnly) { - Readonly = @readonly; + ReadOnly = readOnly; Assignments = new(); } @@ -27,7 +27,7 @@ public override IEnumerator GetEnumerator() => Assignments.GetEnumerator(); protected override string NodeRepresentation() => - Readonly ? "const" : "let"; + ReadOnly ? "const" : "let"; public override AddressedInstructions Accept(InstructionProvider visitor) => visitor.Visit(this); diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs deleted file mode 100644 index 77d4df5e..00000000 --- a/Interpreter.Lib/IR/CheckSemantics/Exceptions/ConstWithoutInitializer.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; - -namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; - -[ExcludeFromCodeCoverage] -public class ConstWithoutInitializer : SemanticException -{ - public ConstWithoutInitializer(IdentifierReference ident) : - base(ident.Segment, $"Const without initializer: {ident.Name}") { } -} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationWithoutInitializer.cs b/Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationWithoutInitializer.cs new file mode 100644 index 00000000..cc1b47a1 --- /dev/null +++ b/Interpreter.Lib/IR/CheckSemantics/Exceptions/DeclarationWithoutInitializer.cs @@ -0,0 +1,11 @@ +using System.Diagnostics.CodeAnalysis; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; + +namespace Interpreter.Lib.IR.CheckSemantics.Exceptions; + +[ExcludeFromCodeCoverage] +public class DeclarationWithoutInitializer : SemanticException +{ + public DeclarationWithoutInitializer(IdentifierReference ident, bool readOnly) : + base(ident.Segment, $"'{(readOnly ? "const" : "let")}' without initializer: {ident.Name}") { } +} \ No newline at end of file diff --git a/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs b/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs index c48953b6..5ac325a7 100644 --- a/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs +++ b/Interpreter.Lib/IR/CheckSemantics/Visitors/DeclarationVisitor.cs @@ -1,5 +1,7 @@ using Interpreter.Lib.IR.Ast; using Interpreter.Lib.IR.Ast.Impl.Nodes.Declarations.AfterTypesAreLoaded; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.ComplexLiterals; +using Interpreter.Lib.IR.Ast.Impl.Nodes.Expressions.PrimaryExpressions; using Interpreter.Lib.IR.CheckSemantics.Exceptions; using Interpreter.Lib.IR.CheckSemantics.Types; using Interpreter.Lib.IR.CheckSemantics.Variables.Symbols; @@ -26,14 +28,19 @@ public Unit Visit(LexicalDeclaration visitable) { if (visitable.SymbolTable.ContainsSymbol(assignment.Destination.Id)) throw new DeclarationAlreadyExists(assignment.Destination.Id); - + var destinationType = assignment.DestinationType?.BuildType( assignment.SymbolTable) ?? "undefined"; + + if (destinationType == "undefined" && + assignment.Source is ImplicitLiteral or ArrayLiteral { Expressions.Count: 0 }) + throw new DeclarationWithoutInitializer(assignment.Destination.Id, visitable.ReadOnly); + visitable.SymbolTable.AddSymbol( new VariableSymbol( assignment.Destination.Id, destinationType, - visitable.Readonly)); + visitable.ReadOnly)); } return default;