feat: add basic lists
This commit is contained in:
@@ -6,6 +6,8 @@
|
|||||||
PUNC_RPAREN=")"
|
PUNC_RPAREN=")"
|
||||||
PUNC_LBRACE="{"
|
PUNC_LBRACE="{"
|
||||||
PUNC_RBRACE="}"
|
PUNC_RBRACE="}"
|
||||||
|
PUNC_LBRACK="["
|
||||||
|
PUNC_RBRACK="]"
|
||||||
PUNC_COMMA=","
|
PUNC_COMMA=","
|
||||||
PUNC_DOT="."
|
PUNC_DOT="."
|
||||||
PUNC_SEMICOLON=";"
|
PUNC_SEMICOLON=";"
|
||||||
@@ -99,11 +101,13 @@ factor ::= unary ( ( OP_SLASH | OP_STAR ) unary )* ;
|
|||||||
|
|
||||||
unary ::= ( OP_BANG | OP_MINUS ) unary | call ;
|
unary ::= ( OP_BANG | OP_MINUS ) unary | call ;
|
||||||
call ::= primary ( PUNC_LPAREN arguments? PUNC_RPAREN | PUNC_DOT IDENTIFIER )* ;
|
call ::= primary ( PUNC_LPAREN arguments? PUNC_RPAREN | PUNC_DOT IDENTIFIER )* ;
|
||||||
primary ::= KW_TRUE | KW_FALSE | KW_NULL | KW_THIS | NUMBER | STRING | IDENTIFIER | PUNC_LPAREN expression PUNC_RPAREN | KW_SUPER PUNC_DOT IDENTIFIER ;
|
primary ::= KW_TRUE | KW_FALSE | KW_NULL | KW_THIS | NUMBER | STRING | IDENTIFIER | PUNC_LPAREN expression PUNC_RPAREN | KW_SUPER PUNC_DOT IDENTIFIER | list ;
|
||||||
|
|
||||||
function ::= IDENTIFIER PUNC_LPAREN parameters? PUNC_RPAREN block ;
|
function ::= IDENTIFIER PUNC_LPAREN parameters? PUNC_RPAREN block ;
|
||||||
parameters ::= IDENTIFIER ( PUNC_COMMA IDENTIFIER )* ;
|
parameters ::= IDENTIFIER ( PUNC_COMMA IDENTIFIER )* ;
|
||||||
arguments ::= expression ( PUNC_COMMA expression )* ;
|
arguments ::= expression ( PUNC_COMMA expression )* ;
|
||||||
|
list ::= PUNC_LBRACK list_items? PUNC_RBRACK ;
|
||||||
|
list_items ::= logic_or (PUNC_COMMA logic_or)* PUNC_COMMA? ;
|
||||||
|
|
||||||
NUMBER ::= DIGIT+ ( PUNC_DOT DIGIT+ ) ?;
|
NUMBER ::= DIGIT+ ( PUNC_DOT DIGIT+ ) ?;
|
||||||
IDENTIFIER ::= ALPHA ( ALPHA | DIGIT | SYM_UNDERSCORE )* ;
|
IDENTIFIER ::= ALPHA ( ALPHA | DIGIT | SYM_UNDERSCORE )* ;
|
||||||
|
|||||||
6
examples/basic/24_list.peb
Normal file
6
examples/basic/24_list.peb
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
let a = [
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c"
|
||||||
|
]
|
||||||
|
print(a)
|
||||||
@@ -54,6 +54,10 @@ class Expr(ABC):
|
|||||||
def visit_fstring_embed_expr(self, expr: FStringEmbedExpr) -> T:
|
def visit_fstring_embed_expr(self, expr: FStringEmbedExpr) -> T:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def visit_list_expr(self, expr: ListExpr) -> T:
|
||||||
|
...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def visit_variable_expr(self, expr: VariableExpr) -> T:
|
def visit_variable_expr(self, expr: VariableExpr) -> T:
|
||||||
...
|
...
|
||||||
@@ -159,6 +163,15 @@ class FStringEmbedExpr(Expr):
|
|||||||
return visitor.visit_fstring_embed_expr(self)
|
return visitor.visit_fstring_embed_expr(self)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class ListExpr(Expr):
|
||||||
|
bracket: Token
|
||||||
|
items: list[Expr]
|
||||||
|
|
||||||
|
def accept(self, visitor: Expr.Visitor[T]) -> T:
|
||||||
|
return visitor.visit_list_expr(self)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class VariableExpr(Expr):
|
class VariableExpr(Expr):
|
||||||
name: Token
|
name: Token
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from src.interpreter.error import PebbleRuntimeError
|
|||||||
|
|
||||||
class StringFormatter:
|
class StringFormatter:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stringify(obj: Any):
|
def stringify(obj: Any, quote_str: bool = False):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
return "null"
|
return "null"
|
||||||
if obj is True:
|
if obj is True:
|
||||||
@@ -19,6 +19,8 @@ class StringFormatter:
|
|||||||
if obj.is_integer():
|
if obj.is_integer():
|
||||||
obj = int(obj)
|
obj = int(obj)
|
||||||
return str(obj)
|
return str(obj)
|
||||||
|
if isinstance(obj, str) and quote_str:
|
||||||
|
return '"' + obj + '"'
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
17
src/core/list.py
Normal file
17
src/core/list.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from typing import Optional, Any
|
||||||
|
|
||||||
|
from src.core.format_spec.string_formatter import StringFormatter
|
||||||
|
|
||||||
|
|
||||||
|
class PebbleList:
|
||||||
|
def __init__(self, items: Optional[list[Any]] = None):
|
||||||
|
self.items: list[Any] = items or []
|
||||||
|
|
||||||
|
def get(self, index: Any):
|
||||||
|
return self.items[index]
|
||||||
|
|
||||||
|
def set(self, index: Any, value: Any):
|
||||||
|
self.items[index] = value
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "[" + ", ".join(map(lambda item: StringFormatter.stringify(item, True), self.items)) + "]"
|
||||||
@@ -2,7 +2,7 @@ from enum import Enum, auto
|
|||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from src.ast.expr import Expr, VariableExpr, LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, AssignExpr, LogicalExpr, \
|
from src.ast.expr import Expr, VariableExpr, LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, AssignExpr, LogicalExpr, \
|
||||||
CallExpr, SetExpr, GetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr
|
CallExpr, SetExpr, GetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr, ListExpr
|
||||||
from src.ast.stmt import Stmt, LetStmt, IfStmt, ExpressionStmt, BlockStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, LetStmt, IfStmt, ExpressionStmt, BlockStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
||||||
from src.core.format_spec.spec import FormatSpec
|
from src.core.format_spec.spec import FormatSpec
|
||||||
@@ -95,6 +95,9 @@ class Formatter(Expr.Visitor[str], Stmt.Visitor[str]):
|
|||||||
res += "}"
|
res += "}"
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def visit_list_expr(self, expr: ListExpr) -> str:
|
||||||
|
return "[" + ", ".join(map(self.format, expr.items)) + "]"
|
||||||
|
|
||||||
def visit_variable_expr(self, expr: VariableExpr) -> str:
|
def visit_variable_expr(self, expr: VariableExpr) -> str:
|
||||||
return expr.name.lexeme
|
return expr.name.lexeme
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr, LogicalExpr, \
|
from src.ast.expr import LiteralExpr, GroupingExpr, UnaryExpr, BinaryExpr, Expr, VariableExpr, AssignExpr, LogicalExpr, \
|
||||||
CallExpr, GetExpr, SetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr
|
CallExpr, GetExpr, SetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr, ListExpr
|
||||||
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
||||||
from src.consts import CONSTRUCTOR_NAME
|
from src.consts import CONSTRUCTOR_NAME
|
||||||
@@ -10,6 +10,7 @@ from src.core.format_spec.string_formatter import StringFormatter
|
|||||||
from src.core.function import PebbleFunction
|
from src.core.function import PebbleFunction
|
||||||
from src.core.instance import PebbleInstance
|
from src.core.instance import PebbleInstance
|
||||||
from src.core.klass import PebbleClass
|
from src.core.klass import PebbleClass
|
||||||
|
from src.core.list import PebbleList
|
||||||
from src.interpreter.environment import Environment
|
from src.interpreter.environment import Environment
|
||||||
from src.interpreter.error import PebbleRuntimeError
|
from src.interpreter.error import PebbleRuntimeError
|
||||||
from src.interpreter.exceptions import ReturnException, BreakException, ContinueException
|
from src.interpreter.exceptions import ReturnException, BreakException, ContinueException
|
||||||
@@ -192,6 +193,12 @@ class Interpreter(Expr.Visitor[Any], Stmt.Visitor[None]):
|
|||||||
return self.stringify(value)
|
return self.stringify(value)
|
||||||
return StringFormatter().format(value, expr.spec)
|
return StringFormatter().format(value, expr.spec)
|
||||||
|
|
||||||
|
def visit_list_expr(self, expr: ListExpr) -> Any:
|
||||||
|
items: list[Any] = []
|
||||||
|
for item in expr.items:
|
||||||
|
items.append(self.evaluate(item))
|
||||||
|
return PebbleList(items)
|
||||||
|
|
||||||
def visit_variable_expr(self, expr: VariableExpr) -> Any:
|
def visit_variable_expr(self, expr: VariableExpr) -> Any:
|
||||||
return self.look_up_variable(expr.name, expr)
|
return self.look_up_variable(expr.name, expr)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from enum import Enum, auto
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from src.ast.expr import Expr, LogicalExpr, VariableExpr, LiteralExpr, GroupingExpr, CallExpr, UnaryExpr, BinaryExpr, \
|
from src.ast.expr import Expr, LogicalExpr, VariableExpr, LiteralExpr, GroupingExpr, CallExpr, UnaryExpr, BinaryExpr, \
|
||||||
AssignExpr, GetExpr, SetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr
|
AssignExpr, GetExpr, SetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr, ListExpr
|
||||||
from src.ast.stmt import Stmt, ForStmt, WhileStmt, LetStmt, ReturnStmt, IfStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ForStmt, WhileStmt, LetStmt, ReturnStmt, IfStmt, FunctionStmt, \
|
||||||
ExpressionStmt, BlockStmt, BreakStmt, ContinueStmt, ClassStmt
|
ExpressionStmt, BlockStmt, BreakStmt, ContinueStmt, ClassStmt
|
||||||
from src.consts import CONSTRUCTOR_NAME
|
from src.consts import CONSTRUCTOR_NAME
|
||||||
@@ -113,6 +113,10 @@ class Resolver(Expr.Visitor[None], Stmt.Visitor[None]):
|
|||||||
def visit_fstring_embed_expr(self, expr: FStringEmbedExpr) -> None:
|
def visit_fstring_embed_expr(self, expr: FStringEmbedExpr) -> None:
|
||||||
self.resolve(expr.expression)
|
self.resolve(expr.expression)
|
||||||
|
|
||||||
|
def visit_list_expr(self, expr: ListExpr) -> None:
|
||||||
|
for item in expr.items:
|
||||||
|
self.resolve(item)
|
||||||
|
|
||||||
def visit_variable_expr(self, expr: VariableExpr) -> None:
|
def visit_variable_expr(self, expr: VariableExpr) -> None:
|
||||||
if len(self.scopes) != 0 and self.scopes[-1].get(expr.name.lexeme) is False:
|
if len(self.scopes) != 0 and self.scopes[-1].get(expr.name.lexeme) is False:
|
||||||
Pebble.token_error(expr.name, "Variable is not initialized.")
|
Pebble.token_error(expr.name, "Variable is not initialized.")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr, LogicalExpr, \
|
from src.ast.expr import Expr, BinaryExpr, UnaryExpr, LiteralExpr, GroupingExpr, VariableExpr, AssignExpr, LogicalExpr, \
|
||||||
CallExpr, GetExpr, SetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr
|
CallExpr, GetExpr, SetExpr, ThisExpr, SuperExpr, FStringExpr, FStringEmbedExpr, ListExpr
|
||||||
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
from src.ast.stmt import Stmt, ExpressionStmt, LetStmt, BlockStmt, IfStmt, WhileStmt, ForStmt, FunctionStmt, \
|
||||||
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
ReturnStmt, BreakStmt, ContinueStmt, ClassStmt
|
||||||
from src.consts import MAX_FUNCTION_ARGS
|
from src.consts import MAX_FUNCTION_ARGS
|
||||||
@@ -369,6 +369,9 @@ class Parser:
|
|||||||
if self.match(TokenType.FSTRING_START):
|
if self.match(TokenType.FSTRING_START):
|
||||||
return self.fstring()
|
return self.fstring()
|
||||||
|
|
||||||
|
if self.match(TokenType.LEFT_BRACKET):
|
||||||
|
return self.list()
|
||||||
|
|
||||||
if self.match(TokenType.NUMBER, TokenType.STRING):
|
if self.match(TokenType.NUMBER, TokenType.STRING):
|
||||||
return LiteralExpr(self.previous().value)
|
return LiteralExpr(self.previous().value)
|
||||||
|
|
||||||
@@ -410,3 +413,14 @@ class Parser:
|
|||||||
|
|
||||||
self.consume(TokenType.FSTRING_END, "Unclosed f-string")
|
self.consume(TokenType.FSTRING_END, "Unclosed f-string")
|
||||||
return FStringExpr(start, parts, self.previous())
|
return FStringExpr(start, parts, self.previous())
|
||||||
|
|
||||||
|
def list(self) -> Expr:
|
||||||
|
bracket: Token = self.previous()
|
||||||
|
items: list[Expr] = []
|
||||||
|
while not self.check(TokenType.RIGHT_BRACKET) and not self.is_at_end():
|
||||||
|
items.append(self.expression())
|
||||||
|
if not self.check(TokenType.RIGHT_BRACKET):
|
||||||
|
self.consume(TokenType.COMMA, "Expected ',' between list items")
|
||||||
|
|
||||||
|
self.consume(TokenType.RIGHT_BRACKET, "Unclosed list")
|
||||||
|
return ListExpr(bracket, items)
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ class Lexer:
|
|||||||
self.add_token(TokenType.LEFT_BRACE)
|
self.add_token(TokenType.LEFT_BRACE)
|
||||||
case "}":
|
case "}":
|
||||||
self.add_token(TokenType.RIGHT_BRACE)
|
self.add_token(TokenType.RIGHT_BRACE)
|
||||||
|
case "[":
|
||||||
|
self.add_token(TokenType.LEFT_BRACKET)
|
||||||
|
case "]":
|
||||||
|
self.add_token(TokenType.RIGHT_BRACKET)
|
||||||
case ",":
|
case ",":
|
||||||
self.add_token(TokenType.COMMA)
|
self.add_token(TokenType.COMMA)
|
||||||
case ".":
|
case ".":
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ class TokenType(Enum):
|
|||||||
RIGHT_PAREN = auto()
|
RIGHT_PAREN = auto()
|
||||||
LEFT_BRACE = auto()
|
LEFT_BRACE = auto()
|
||||||
RIGHT_BRACE = auto()
|
RIGHT_BRACE = auto()
|
||||||
|
LEFT_BRACKET = auto()
|
||||||
|
RIGHT_BRACKET = auto()
|
||||||
COMMA = auto()
|
COMMA = auto()
|
||||||
DOT = auto()
|
DOT = auto()
|
||||||
SEMICOLON = auto()
|
SEMICOLON = auto()
|
||||||
|
|||||||
Reference in New Issue
Block a user