From 8f0d3bf5f232150213ed5fdb38874e877eb096f1 Mon Sep 17 00:00:00 2001 From: Vardan2009 <70532109+Vardan2009@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:45:18 +0400 Subject: [PATCH 1/2] Added modifiers (`readonly`, `private`) --- eiger/Execution/BuiltInTypes/Value.cs | 27 ++++++++-------- eiger/Execution/Interpreter.cs | 45 ++++++++++++++++++++------- eiger/Parsing/Parser.cs | 39 +++++++++++++++++++++-- 3 files changed, 83 insertions(+), 28 deletions(-) diff --git a/eiger/Execution/BuiltInTypes/Value.cs b/eiger/Execution/BuiltInTypes/Value.cs index 15b6be3..5c2ebdc 100644 --- a/eiger/Execution/BuiltInTypes/Value.cs +++ b/eiger/Execution/BuiltInTypes/Value.cs @@ -5,7 +5,7 @@ namespace EigerLang.Execution.BuiltInTypes; public class Value(string _filename, int _line, int _pos) { - public bool isReadonly = false; + public List modifiers = []; public string filename = _filename; public int line = _line, pos = _pos; @@ -101,19 +101,20 @@ public virtual Value GetLength() public virtual Value GetAttr(ASTNode attr) { + Value retVal; if (attr.type == NodeType.AttrAccess) - { - return GetAttr(attr.children[0]).GetAttr(attr.children[1]); - } - if (attr.value == "asString") - { - return new String(filename, line, pos, ToString() ?? ""); - } - if (attr.value == "length") - { - return GetLength(); - } - throw new EigerError(filename, line, pos, "Attribute not found", EigerError.ErrorType.RuntimeError); + retVal = GetAttr(attr.children[0]).GetAttr(attr.children[1]); + else if (attr.value == "asString") + retVal = new String(filename, line, pos, ToString() ?? ""); + else if (attr.value == "length") + retVal = GetLength(); + else + throw new EigerError(filename, line, pos, "Attribute not found", EigerError.ErrorType.RuntimeError); + + if (retVal.modifiers.Contains("private")) + throw new EigerError(filename, line, pos, "Attribute is private", EigerError.ErrorType.RuntimeError); + + return retVal; } public virtual void SetAttr(ASTNode attr, Value val) diff --git a/eiger/Execution/Interpreter.cs b/eiger/Execution/Interpreter.cs index 9ae5a53..f472785 100644 --- a/eiger/Execution/Interpreter.cs +++ b/eiger/Execution/Interpreter.cs @@ -28,11 +28,11 @@ class Interpreter public static BuiltInFunctions.ExitFunction exitFunction = new(); public static Number fgColor = new("", 0, 0, (int)ConsoleColor.Gray) { - isReadonly = true + modifiers = ["readonly"] }; public static Number bgColor = new("", 0, 0, (int)ConsoleColor.Black) { - isReadonly = true + modifiers = ["readonly"] }; // global symbol table @@ -267,14 +267,20 @@ public static (bool, bool, Value) VisitBlockNode(ASTNode node, Dictionary modifiers = pack[0] ?? new List(); + + if (symbolTable.ContainsKey(varName)) + throw new EigerError(node.filename, node.line, node.pos, $"Variable {varName} already declared", EigerError.ErrorType.RuntimeError); Value v = node.children.Count == 1 ? VisitNode(node.children[0], symbolTable).Item3 : new Nix(node.filename, node.line, node.pos); - symbolTable.Add(node.value, v); + v.modifiers = modifiers; + + symbolTable.Add(varName, v); return (false, false, v); } @@ -347,7 +353,9 @@ public static (bool, bool, Value) VisitBlockNode(ASTNode node, Dictionary modifiers = pack[0] ?? new List(); // a symbol with that name already exists if (symbolTable.ContainsKey(funcName) && funcName != "") @@ -368,11 +376,16 @@ public static (bool, bool, Value) VisitBlockNode(ASTNode node, Dictionary modifiers = pack[0] ?? new List(); if (symbolTable.ContainsKey(funcName) && funcName != "") throw new EigerError(node.filename, node.line, node.pos, $"{funcName} already declared", EigerError.ErrorType.RuntimeError); @@ -406,7 +421,10 @@ public static (bool, bool, Value) VisitBlockNode(ASTNode node, Dictionary symbolTable) { Value leftValue = GetSymbol(symbolTable, node.children[0]); - if (leftValue.isReadonly) + if (leftValue.modifiers.Contains("readonly")) throw new EigerError(leftValue.filename, leftValue.line, leftValue.pos, $"{leftValue} is read-only!", EigerError.ErrorType.RuntimeError); SetSymbol(symbolTable, node.children[0], rightSide); @@ -484,7 +502,7 @@ private static Value HandleCompoundAssignment(ASTNode node, Value rightSide, Dic { Value leftValue = GetSymbol(symbolTable, node.children[0]); Value newValue = operation(leftValue, rightSide); - if (leftValue.isReadonly) + if (leftValue.modifiers.Contains("readonly")) throw new EigerError(leftValue.filename, leftValue.line, leftValue.pos, $"{leftValue} is read-only!", EigerError.ErrorType.RuntimeError); else SetSymbol(symbolTable, node.children[0], newValue); @@ -548,6 +566,9 @@ private static (bool, bool, Value) VisitAttrAccessNode(ASTNode node, Dictionary< currentNode = currentNode.children[1]; } + if (v.modifiers.Contains("private")) + throw new EigerError(node.filename, node.line, node.pos, "Attribute is private", EigerError.ErrorType.RuntimeError); + if (v is BaseFunction f && currentNode.type == NodeType.FuncCall) { List args = []; // prepare a list for args diff --git a/eiger/Parsing/Parser.cs b/eiger/Parsing/Parser.cs index 70bc8f6..f685801 100644 --- a/eiger/Parsing/Parser.cs +++ b/eiger/Parsing/Parser.cs @@ -31,6 +31,11 @@ public class Parser(List tokens) TokenType.EQ, TokenType.PLUSEQ,TokenType.MINUSEQ,TokenType.MULEQ,TokenType.DIVEQ,TokenType.EQEQ, TokenType.NEQEQ,TokenType.GT, TokenType.LT, TokenType.GTE, TokenType.LTE, }; + readonly List varModifiers = new() + { + "readonly", "private" + }; + string path = ""; // parse the root @@ -149,6 +154,20 @@ ASTNode FuncDefStatement(bool includeName = true) Token funcTok = Peek(); Match(TokenType.IDENTIFIER, "func"); + List modifiers = []; + + while (Peek().type == TokenType.IDENTIFIER && varModifiers.Contains(Peek().value)) + { + string modifier = Peek().value ?? throw new EigerError(path, Peek().line, Peek().pos, $"Modifier has no value", EigerError.ErrorType.RuntimeError); + + if (modifiers.Contains(modifier)) + throw new EigerError(path, Peek().line, Peek().pos, $"Double modifier {modifier}", EigerError.ErrorType.RuntimeError); + else + modifiers.Add(modifier); + + Advance(); + } + // get func name string funcName = ""; @@ -156,7 +175,7 @@ ASTNode FuncDefStatement(bool includeName = true) funcName = Advance().value ?? ""; // create func def node - ASTNode node = new(NodeType.FuncDef, funcName, funcTok.line, funcTok.pos, path); + ASTNode node = new(NodeType.FuncDef, new dynamic?[2] { modifiers, funcName }, funcTok.line, funcTok.pos, path); // create list for args List args = []; @@ -368,12 +387,26 @@ ASTNode LetStatement() Token letToken = Peek(); Match(TokenType.IDENTIFIER, "let"); + List modifiers = []; + + while (Peek().type == TokenType.IDENTIFIER && varModifiers.Contains(Peek().value)) + { + string modifier = Peek().value ?? throw new EigerError(path, Peek().line, Peek().pos, $"Modifier has no value", EigerError.ErrorType.RuntimeError); + + if (modifiers.Contains(modifier)) + throw new EigerError(path, Peek().line, Peek().pos, $"Double modifier {modifier}", EigerError.ErrorType.RuntimeError); + else + modifiers.Add(modifier); + + Advance(); + } + Token variableName = Advance(); - ASTNode letNode = new ASTNode(NodeType.Let, variableName.value, letToken.line, letToken.pos, path); + ASTNode letNode = new(NodeType.Let, new dynamic?[2] { modifiers, variableName.value }, letToken.line, letToken.pos, path); // if the variable has an initial value (let x = 10) - if(Peek().type == TokenType.EQ) + if (Peek().type == TokenType.EQ) { Match(TokenType.EQ); letNode.AddChild(Expr()); From fa7eeecd9fd5bbdc5df9f5b07a230f1857b5627d Mon Sep 17 00:00:00 2001 From: Vardan Petrosyan <70532109+Vardan2009@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:49:20 +0400 Subject: [PATCH 2/2] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0ca2acd..00eb069 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,8 @@ ``` class Person - let name - let surname + let private name + let private surname ~ constructor func new(name, surname)