Esta en esta primera parte detectaremos las palabras (tokens) que tenemos en el texto de entrada.
Crear la clase Lexer
, esta es la encargada de crear o producir las palabras (tokens).
Crear la clase SyntaxToken
, representa un Token en nuestro lenguaje, esta clase conoce el tipo, la posicion del token y su valor.
Crear SyntaxKind enum
, que almacena todos los tipos de palabras de nuestro lenguaje.
Clase lexer
, agregar un nuevo metodo NextToken
, este buscara la siguiente palabra y la retornara, de acuerdo a la posicion actual.
Aqui se define los tokens que queremos encontrar, ejem: simbolos, numeros, espacios en blanco, etc
.
Clase lexer
, crear la propiedad Current
:
para hacer seguimiento al character actual del texto de entrada
Segunda parte 1:
Basicamente leeremos todo el texto de entrada, y guardaremos todos los tokens reconociendo sentencias.
Crear la clase Parser
, es el encargado de crear sentencias con los tokens, como si fueran notas sintacticas.
- Esta clase tambien agrega a la sentencia un ultimo token, que determina el final del texto.
Clase Parser
, creamos el metodo Peek
: Nos ayuda a seleccionar un token, o retornar el ultimo si ya no hay tokens en la lista.
Clase Parser
, creamos la propiedad Current
: Usa el metodo peek, para seleccionar el token actual.
Se necesita la creacion de nodos para continuar...
Empezamos con el diseño del arbol que nos ayudara a interpretar o resolver el texto de entrada.
Texto de entrada: 1 + 2 * 3
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Arbol:
+
/ \
1 *
/ \
2 3
Crear la clase abstracta SyntaxNode
, que es la base de todos nodos en esta aplicacion, la clase ExpresionSyntax
deribara de este:
- Ahora podremos crear los distintos tipos de expresiones en los nodos, ejm: NumberSyntax, BinarySyntax, etc.
Procedimiento para agregar un tipo de expresion (Siguiendo los ejemplos se puede agregar cualquier tipo de ExpresionSyntax en el futuro follow the link). Ejemplos:
-
3.1 Crear la clase
NumberExpresionSyntax
, que define los tokens de numeros del texto, cada objeto es un Numbertoken. -
3.2 Crear la clase
BinaryExpresionSyntax
, representa una operacion, cada objeto tiene una expresion a la izquierda, un operador y una expresion a la derecha.
Continuacion de la segunda parte...
Se define la logica para unir e interpretar los nodos segun el orden de operacion de realizan.
Clase Parser
, crear el metodo Match
, para comprobar el correcto tipo del token.
Clase Parser
, crear los metodos Parse
y ParsePrimaryExpression
, para analizar la expresion en un nodo, y descomponerla si es necesario.
En la clase Program
, crear el metodo estatido PrettyPrint
, esta parte es solo para mostrar la estructura de los nodos en forma de arbol que el programa esta siguiendo.
Implementa el diagnostico de errores, Identifica los tokens malos.
Crear la clase SyntaxTree
, esta sera un tipo que representa todas las entradas una forma de limpiar el codigo.
Con esto se modificando el metodo Parse
, en la clase Parser
.
Ahora el metodo Parse
revisa que la expresion se haya terminado de leer.
Evalua las expresiones en cada nodo del arbol
Create Evaluator class.
Clase Evaluator
, crear los metodos Evaluate
y EvaluateExpression
, que trabajan con los tipos de expresiones de nuestra aplicacion, ejm: BinaryExpressionSyntax, NumberExpressionSyntax, etc.
Triki tip Sexta parte 2:
- Corrige el error, para evaluar los operadores
*, /
con mayor prioridad que los operadores+, -
Dividimos ParseExpression
method en PaseFactor
y ParserTerme
.
Add Parenthesis expresion.
Crear la clase ParenthesizedExpressionSyntax
.
Modificar el metodo ParsePrimayExpression
, en la clase Parser
y Agregar el metodo ParseExpresion
.
Modificar el metodo EvaluateExpression
After clean the code:
Parser
class, add the GetBinaryOperatorPrecendence
method, to defice the priority of operatores. This method simplifies the addition of other priority operators.
examples:
+2
-1 * -3
-(4 + 7)
Term: -(1 + 2)
~~~~~~~~~~~~~~
Tree:
-
|
+
/ \
1 2
Create de UnaryExpressionSyntax
class
* Contains an operator (Plus or Minus)
* Contains an operand (Expression to evaluate)
Add a way to evaluate the unary expression on Evaluate
class.
SyntaxFacts
class, add the unary precedence, with longer priority to avoid bugs.
Term: -1 + 2
~~~~~~~~~~~~
Bad precedence:
-
|
+
/ \
1 2
Correct precedence:
+
/ \
- 2
|
1
Parser
class, parser the unary expression in ParseExpression
method.
Give the capacity to the compiler to know what type are each token.
Create some class about node representation.
Create the Binder
class, this class handler the logic what the type-checker would do.
Add the handler errors in the Binder class, to avoid cascade errors for now.
Change the Evaluator
class, to work with nodes representation.
Class Program
, modify the Main
method and separate the code from the binder
file into several files.
App recognize true
and false
keywords
Class lexer
, modify the Lex
method to recognize letters.
Class Parser
, convert true
and false
keywords into LiteralExpressionSyntax
.
Class Evaluator
, change the return of Evaluate, EvaluateExpression
methods to object
type.
The app is case sensitive
yet.
There are a bug:
> false
False
> true
False
Class Lexer
, and new operators '!, &&, ||, ==, !='.
Class SyntaxFacts
, Add precedence to new operators.
Class Binder
, handler Booleans types.
Class Evaluator
, can resolve expressions with new operators.
The bug later was fixed.
Class Binder
, deleted BindBinaryOperatorKind
and BindUnaryOperatorKind
methods, to add new classes that handler bound operators.
Modify BoundBinaryOperator
class to add new items of ==, !=
to work with int
types.
Fix the Bug in the Bilder
class, that returned a bad type.
Class Program
, Fix diagnostics error, binder's Diagnostics weren't concatenated.
Fix 'BoundBinaryOperator' class. Remove duplicate code.
Class Binder
, Change <> characters by ''.
Add parentheses to the new tree structure in the 'binder' class.
Fix the invalid 'BoundNodeKind.UnaryExpression' into a binary expression
Create a new library project, and move the CodeAnalysis
folder to here.
Create a public class to compile de code, and show evaluation results.
Use library in Program
class.
Centralizing it into a single type, and report diagnostic spans.
Create a TextSpan
class, to handler length info.
Create a new Diagnostics
and DiagnosticsBag
classes, to create a list of different types of diagnostics to apply into the app.
Fix the error to report positions in operant tokens
of 2 characters.
Program
class, render the diagnostics and spans in a nice way.
Create the NameExpressionSyntax
class: represents the identifier of variable
Create the AssignmentExpressionSyntax
class: it is a way to represent a expression of assignment, contain:
IdentifierToken
: will be the identifier- `EqualsToken
Expression
: will be the expression to assignment
Update BindExpression
method, add new method for parenthesized expression.
Lexer
class, add the assignment operator '='.
Parser
class, add new method to parse
assignment expressions.
Compilation
class, use dictionary concept to place variables, and request their values.
Create new bound classes for assignment and variable.
BoundAssignmentExpression
handler name, and expression to be assignmentBoundVariableExpression
handler name and types
Implement the new logic for variables.
Select the bound expression to variables, and add diagnostic. when doesn't exist a variable In this fase the assignment is worked only to int type.
App can run and, use a new way to work with int and bool types
Use a class to place and request variables. To look similar to and API
Replace binding logic with proper symbols, of variables.
Add new Test project, and Create LexerTest
file.
Expose method.
SyntaxTree
class, add the ParseTokens
method, to accesses the Lexer
methods, since the most part of them are private.
First approach, need to convert entry into correct tokens.
input:
==
==!
=!=
LexerTest
class, add the GetToken
method. this method tests a single token.
- Define all simple text that you hope that will be a token plus their syntax kind.
- Add
Theories
andmemberData
decorators, to loop theGetToken
method with another method.
LexerTest
class, add the GetTokenPairs
method, that tests a pair of tokens
- Use the
GetTokens
method to obtains tokens - To work need a condition, and define the
RequiresSeparator
method.
We test white spaces, add the GetSeparators
methods
- Concatenate this enumerable result with
GetTokens
result, to tests them like singles tokens
Add test to pipe-line
Convert to public the SyntaxFacts
class.
Add a new method to map from keyword, in SyntaxFacts
class, the GetText
method, to return the text value of a operand token's syntax kind.
- This is because we have many operators with a fixed text.
Create SyntaxFactsTest
, to test the GetText
method.
To test the correct structure of the tree
Create the Parser
class.
Add other methods to SyntaxFacts
class, to get a list of operator kinds.
Test binary expression, analyzing the operators precedence that there are in an expression:
SyntaxFacts
class, add methods GetUnaryOperatorKinds
and GetBinaryOperatorKinds
These methods take the precedence to return kinds.
to make that, add a new class AssertingEnumerator
. This tests the way to build the tree and test the different Node and tokens that it has.
handler assert each node and token
ParserTests
class, add the test to be honor at binary precedence ParserBinaryExpressionHonornsPrecedences
method.
Test the building of a binary expression tree
Example, if have :
- op1 = precedence operator 1
- op2 = precedence operator 2
if (op1 >= op2)
op2
/ \
op1 c
/ \
a b
else
op1
/ \
a op2
/ \
c b
ParserTests
class, Add tests to ensure we honor unary and binary precedences, add ParserUnaryExpressionHonornsPrecedences
method.
Test the building of a unary expression tree
Example, if have :
- unary = precedence operator 1
- binary = precedence operator 2
if (unary >= binary)
binary
/ \
unary b
|
a
else
unary
|
binary
/ \
a b
Test unary and binary evaluations, with numbers and booleans. and variables assignation.
#Compiler part 5
Optimize the Lex
method, to match faster to dispatch, jumping to the corresponding case label.
Add white space more common like cases, but maintain a method to match other types of white spaces Order the default case by the most common occurrences first.
Refactor the GetTokens
method, divide the large list into fixedTokens
, these are defined in the SyntaxFacts
class, and dynamicTokens
that could have any value.
Create LexerTestsAllTokens
method, to test we text all token kinds
Separate the 'Evaluate expression' method to read more easily and substantially
- Chance if - else conditions by switch cases
Separate the ParsePrimaryExpression
method, cleaning the switch case.
To improve the API
Install System.Collections.Immutable
package, in the library project.
Change the IReadOnlyList
to ImmutableArray
for diagnostic
parameters, because nobody wanted to cast
all time this parameter and modify the data parameter.
Use ImmutableArray in Parser class.
Get SyntaxNode.GetChildren non-virtual.
Make more efficient way to get elements. and avoid some of the downfalls when you do a evaluation of things and end up in recursion in parts that you're not supposed to be into.
Refactor the GetChildren
method, using Reflection to obtain all class's properties that call this method
- Delete the other methods that overwrite this, in the child classes.
- The order of reflection return the elements is defined by the order of properties are declared into the class.
Construct the span over the first and last children.
Create TextSpan.FromBounds()
helper method, to return a new TextSpan
class.
(Not super efficient but it will work) SyntaxNode
class, add virtual Span
property, implement TextSpan.FromBounds()
method, using the span of children.
Change Span
property of SyntaxToken
to override.
Change the app that is based in positions, that to reports error shows a bunch numbers of length of error, instead we want to show the line and column where is happened the error.
We will remember effectively how long the lines are. And given a position we can compute the line number.
An new concept to API
Create 'Text' namespace and move 'TextSpan' into.
Create SourceText
class, that handles information.
Create TextLine
class, that is the definition of a line.
SourceText
class
- Create
ParseLines
method. that parse each line form the text. - Create
GetLineBreakWidth
method, that controls when a line is on the end. - Create
AddLine
method. Add each parse line to source result.
Apply this concept to look line index
SourceText
class, create GetLineIndex
method, that look for an line index into Lines
immutable Array.
Override ToString
method.
SourceText
class
- return string of text
- return string of text passing the star position and the length
- return string of text passing span parameters
TextLine
class
- return text passing span parameters
Implement SourceText
into the API
- Fix a bug in
SourceText.GetLineIndex
method.
Program
class, show line and character when an error occurs.
- Fix a bug of null reference for cases where the token was inserted,
SyntaxToken
class.
Program
class, add textBuilder
parameter to handles multiple lines on console.
- Make sure that the last line is added to
SourceText
Create new name space to test Text
Add Test: To check that the correct number of lines is added to the 'SourceText' class.
Add Colorization to REPL
Add compilation unit:
- The problem is when we need to pass multiples declarations or statements we don't have the singular root object
- There isn't an array of expression
- To pass a expression we have to pass the whole SyntaxTree first, and SyntaxTree isn't a node.
(in C++ each source file is effectively compiled to its own obj file) Create root node:
- Create
CompilationUnitSyntax
class: Represent the entire file.
- Modify
SyntaxTree
constructor. - Add
ParseCompilationUnit
method toParser
class - Use the correct expression in
Compilation
class and tests.
Things to change:
- The currency way to map variables is with dictionary in the binder.
- Binder should not even care about the values it just cares about the variables themselves
- Reassignment variables with different types.
- Support nesting scopes
- Support shadowing scopes
Create BoundScope
class
- With a private dictionary, to look up variables names fast.
- Add
parent
parameter to handler scopes nested. - Add
TryDeclare
method to report error when a variable already exist in the same scope or. - and
TryLookup
method look for the variable on all scopes.
Create BoundGlobalScope
class, catches the root of the program.
- This has access to diagnostics, variables, expression in the program.
Binder
class, now return BoundGlobalScope
with all data.
Handles variables into the scope.
Compilation
class is modify to work with BoundGlobalScope
.
- There isn't a scope yet.
Compilation
class, convert the global scope local variable to parameter
- It's not a good idea for thread safely
Global scope will give the same result
- Make thread safely
- Use a pattern in
GlobalScope
property
Chain previous submissions
submissions 3 -> submissions 2 -> submissions 1
Binder
class, create CreateParentScopes
method to map all scopes previous.
- It's a nested scope
Compilation is saved in previous variable to use it next time
- Chain the diagnostics.
- Add
#reset
command to reset scopes.
- Improve the behavior when declare variables.
- Add diagnostic to raise the error "cannot convert the types"
- Doesn't have to declare a variable with different types in the same scope.
- Extract 'ParseExpression' method into tests.
Can chain one into the other. A single statement can be a block in which you nesting
Create the StatementSyntax
class, and BlockStatementSyntax
class, that represent a statements
Create the 'ExpressionStatementSyntax' class, in which can define the roles to valid statements. or what expression will be considered valid.
Is valid:
a++ , a = 10 , a = a , M()
Is not valid:
a + 1
Add to Lexer
class and SyntaxFact
class the brace symbols '{}' to match them.
CompilationUnitSyntax
class, apply the StatementSyntax
concept instead of ExpressionSyntax
.
ParserTest
, in ParseExpression
method add a new assert before return the expression.
Update Parser
class, to parse statement expression.
Add BoundStatement
, BoundBlockStatement
and BoundExpressionStatement
concept into semantic logic.
Binder
class, Add BindStatement
method, to match with statements concepts.
- Update
BoundGlobalScope
to receive statements instead expressions.
Evaluator
class
- Add
EvaluateStatement
method, to match with statements concepts to evaluate internal expressions. - Create
lastValue
property map for the statements.
Can not reassignment a variable with another type of data.
people not implicitly creating them on first assignment.
Create VariableDeclarationSyntax
class, where define how will be the variables
var x = 10
let x = 10
Add 'let' and 'var' keywords to SyntaxFact
class.
Parser
class, add ParseVariableDeclaration
method that handles declaration variables concept.
- convert
if
conditional intoswitch
,ParseStatement
method.
Add VariableDeclarationSyntax
class
binder
class, add BindVariableDeclaration
methos to analyze if is keyword of variable is let
or var
.
- Add
isReadOnly
parameter toVariableSymbol
class.
Create BoundVariableDeclaration
class
Add new reports to diagnostic class.
Evaluator
class, add EvaluateVariableDeclaration
method to handler variables.
case:
[]
show the location of expected errors.
{
let = [100]
x [=] 10 <- a variable `let` is read-only
}
Create AnnotatedText
class into Texts project.
AnnotatedText
class, add Parse
method, to analyze the input text without worry for whitespaces.
Create the Unindent
method to take care of unindenting.
Delete extra whitespaces:
var textToTest = @"
~~~~~~~~~~{
~~~~~~~~~~ var x = 10
~~~~~~~~~~ let x = 2
~~~~~~~~~~}
~~~~~~";
- Provide
ToString
method toTextSpan
class - Mark error messages consistent,
DiagnosticBag
class
EvaluationTests
class, add test cases to report error for span in the text, Extract 'AssertValue' method.
- Fix 'IdentifierToken' to 'EqualsToken' to report error in read-only variables,
Binder
class.
< > <= >=
Lexer
class, add operators symbols.
SyntaxFacts
class, add precedence and text to conditional operators.
Add them to operator table, BoundBinaryOperator
class.
- Compare between
int
Add operators to 'Evaluator' class
Add tests cases to conditional operators
- Create
IfStatementSyntax
class like IfStatementSyntax - Create
ElseClauseSyntax
class like a node, because not need an expression or values.
SyntaxFacts
class, add keywords
Parser
class, add ParseIfStatement
method to create new if
statement, this calls ParseElseClause
method
Binder
class, add BindIfStatement
method and override the BindExpression
method to check the type of condition.
- Create
BoundIfStatement
class.
Evaluator
class, add EvaluateIfStatement
that evaluates ThenStatement
or ElseStatement
.
EvaluationTests
class, Add if-else cases to test.
- Add
while
keyword toSyntaxFacts
class. - Add
ParseWhileStatement
method toParser
class. - Create
WhileStatementSyntax
class. - Create
BoundWhileStatement
class. - Add
BindWhileStatement
method toBinder
class. - Add
EvaluateWhileStatement
method toEvaluator
class. - Add test cases.
for i = 0 to 10
{
}
- Add
for
keyword toSyntaxFacts
class. - Create
ForStatementSyntax
class. - Add
ParseForStatement
method toParser
class. - Add
BindForStatement
method toBinder
class. - Create
BoundForStatement
class - Add
EvaluateForStatement
method toEvaluator
class. - Add tests.
Ensure binder doesn't crash when binding fabricated identifiers
* Modify ParseBlockStatement
method in Parser
class, to skip to next position when parse statement parse void.
* Add test to control this.
Modify ParseBlockStatement
method in Parser
class:
- If
ParseStatement()
did not consume any tokens, need to skip the current token and continue in order to avoid an infinite loop. - Do not need to report an error, because already tried to parse an expression statement and reported one.
Modify BindNameExpression
method in Binder
class:
- This means the token was inserted by the parser.
- We already reported error so we can just return an error expression.
Support for bitwise operators
- Create test cases
- Add
~
,&
,|
and^
Bitwise operators toLexer
class. - Add precedence of bitwise operators and get text cases in
SyntaxFacts
class. - Add operators to unary operators table in
BoundUnaryOperator
class. - Add operators to binary operators table in
BoundBinaryOperator
class. - Add evaluate cases in
Evaluator
class.
A way to get the children in BoundNode
, 'Copy all of SyntaxNode
'.
- Add
WriteNode
method.
Add a new command #showProgram
to Enabled bound trees to show.
- Create
EmitTree
to write trees.
Change color by each type of bound node.
- Add
GetColor
method inBoundNode
class.
Handle binary and unary expressions
- Add
GetText
method inBoundNode
class.
BoundNode
class. Add more properties to show.
- Add
GetProperties
method that return an IEnumerable - Delete
WriteNode
method, to implement it intoPrettyPrint
method. - Loop for properties and write them with colors.
Add methods to rewrite Statements and Expressions.
Create Lower
method to rewrite a statement.
Compilation
class
- Create
GetStatement
method that will Lower the global scope statement. - Change all
GlobalScope.Statement
forGetStatement()
.
want to convert this:
for <var> = <lower> to <upper>
{
<body>
}
to:
------------------->
{
var <var> = <lower>
let <upperBound> = <upper>
while (<var> <= <upperBound>)
{
<body>
<var> = <var + 1>
}
}
Lowerer
class, overrideRewriteForStatement
method.Evaluator
class, deleteEvaluateForStatement
method because we don't use it anymore.
"We don't add them to Syntax, because we just want to have it in internal representation."
Create LabelSymbol
class in Nova.CodeAnalysis
namespace.
LabelStatement
declare the target.GotoStatement
jumps to the target.
Create BoundGotoStatement
class, BoundConditionalGotoStatement
class and BoundLabelStatement
class.
Add LabelStatement
, GotoStatement
and ConditionalGotoStatement
cases to rewriter concepts.
Lowerer
class, create GenerateLabel
method, to return numerated labels.
with Gotos
We want to convert this:
- simple case:
if <condition>
<then>
to:
--------------->
gotoFalse <condition> end
<then>
end:
==============================
- complex case:
if <condition>
<then>
else
<else>
to:
--------------->
gotoFalse <condition> else
<then>
goto end
else:
<else>
end:
Lowerer
class, override RewriteIfStatement
method.
We want to convert this:
while <condition>
<body>
to:
------------------->
goto check
continue:
<body>
check:
gotoTrue <condition> continue
end:
Lowerer
class, override RewriteWhileStatement
method.
Evaluator
class, modify Evaluate
method to add a way to select evaluate the things.
- Delete
EvaluateStatement
method because we don't use evaluate if, while, or block statement anymore.
Read-Eval-Print-Loop Keeping track to variables or language
- Support multi-line editing, syntax coloration and history.
Create Repl
class that contains all code to run the program.
Create NovaRepl
class that handles with the language specific stuff.
Change the control flow current in program, to return at a variable and you can update it in the input.
- Return to a particular line
- Typing or deleting redraw
Repl
class, convert the document input to local.
Create SubmissionView
class that handler the input like a document.
Render
method help to display document and set the cursor into right position.EditingSubmission
class was modify to handler the inserted keys- the
enter
orcontrolEnter
key return all document.
- the
Fix unexpected behavior that continue running with empty text.
Handle commands.
- Fix the length covered by the right key
- Deleted unusable method
Handle key modifiers, covered:
- Backspace key
- Delete key
- Home key
- End key
- Tab key
- Escape Key
- Fix the new line error
- Fix the adding whites space in a new line
Handle page up - page down.
Create a list of string that carry all input data
Crate ClearHistory
method that clean history.
Handle pageUp
and pageDown
key to go through the history.
- Create
UpdateDocumentFromHistory
method.
Fix errors:
- Solved exception when 'pageDown' key is clicked
- Fix cursor position and extra data is cleaned
- Create
RenderLine
method inRepl
class. - Override
RenderLine
method inNovaRepl
class, add color to specific tokens;
- Fix output, correcting evaluation result that overwrite code from history
- When use 'pageUp' or 'pageDown'
- Use 'controlEnter' key to insert a new blank line below
Add 'delete between lines' behavior with 'Backspace' key
- Avoid exception when accessing empty history
- When use
pageUp
orpageDown
keys without history.
- When use
- Check whether the last token is missing
- Fix infinite loops when a bad typing occur
Add 'delete between lines' behavior with 'Delete' key
- Move GetLastToken() to 'SyntaxNode' class.
- Prettify the output
- add coloration to Identifier
- add coloration to numbers
Sometimes our heuristic for detecting whether the submission is complete doesn't work, in which case we want the user to have the ability to force the completion. We do this by adding two blank lines.
NovaRepl
class, modifyIsCompleteSubmission
method to end the program when detect two blank lines.
When parsing tokens only, we currently have no way to get access to the lexer's diagnostics. This adds an optional out parameter.
The real fix, of course, would be to mirror what Roslyn is doing, which is exposing the diagnostics on the actual tokens, which makes the output neatly self-contained.
SyntaxTree
class, overload theParseTokens
method and change the return type.
To catch the quote symbol into a string, use helpers:
the input:
---------
Test " asdsd
the output:
---------
one way:
"Test \" asdsd"
second way:
"Test "" asdsd" <--
Lexer
class, match "
quote symbol, and add ReadString
method.
- Return report when a string is incomplete
DiagnosticBag
class, add a report to ReportUnterminatedString
Parser
class, add ParserStringLiteral
method.
LexerTests
class, add LexerLexesUnterminatedString
method to test a specific case:
"\"Test"
That is because LabelSymbol
was used only for binder to represent all loops.
- Also, this class is an internal helper.
Move
BoundLabel
class to Binding namespace.
- Move 'VariableSymbol' to a separate namespace
- Enables to add more Symbols.
- Create
Symbol
abstract class. - Create
SymbolKind
enum, that has all type of symbols
Create TypeSymbol
class to replace 'System.Type'
Add concept of error, Add 'TypeSymbol.Error' to represent unbindable expressions This avoids cascading errors when part of an expression cannot be bound. Higher nodes, such as binary expressions, can detect this case and bail early.
Add Error
type in TypeSymbol
class.
Create BoundErrorExpression
class, to return it into:
BindUnaryExpression
method, when the type is incorrectBindBinaryExpression
method, when the one side's type is incorrect or operator is missingBindNameExpression
method, if we don't know what name it is or when we can't lookup the name
Not return it in:
BindAssignmentExpression
method, is not useful, because assignments are right associative and need more information.BindLiteralExpression
are always define.
BoundTreeRewriter
, add 'ErrorExpression' to 'RewriteExpression' method.
- Or incomplete Assignation statements
BoundBinaryOperator
class, add new operator to the table, to handler string.Evaluator
class, evaluate 'adding' string.Evaluator
class, Fix bugs of conditions, remove excess brackets.
Repl
class, Change coloration of '>>, ·' symbols.NovaRepl
class, Add highlighting color for string tokens.
- Create
ParameterSymbol
class, used in functions, It inherit fromVariableSymbol
- Create
FunctionSymbol
class, that contains an Arrays of parameters. - Add
Void
type toTypeSymbol
class, that it's need to some functions. - Create
BuiltinFunctions
class, In which define all functions to be use.
Call expression, some examples:
Some calls:
* print("Hello")
* add(1, 2)
- Create
CallExpressionSyntax
class, has the syntax of a call of function, but need arguments. - Create
SeparatedSyntaxList<T>
class, whereT
=SyntaxNode
this return:- the quantity of arguments that has
- Arguments
- Separators
- Arguments (Nodes) and separators
Interpret the input: add(1, 2)
:
Lexer
class, match ',' symbol- 'SyntaxFacts' class, handler
CommaToken
. - 'Parser' class, modify the case to
IdentifierToken
:- Add
ParseNameOrCallExpression
method, who identify if parseNameExpression
or parse 'CallExpression'. - Add
ParseCallExpression
method, that collects its parameters and arguments. - Add
ParseArguments
method, add all tokens inside of Parenthesis.
- Add
Binder
class, createBindCallExpression
, not implemented yet. Return an Error.
Show CommaToken
when printing parser trees
- Create
SeparatedSyntaxList
like abstract class, to generalice the return of Arguments (Nodes) and separators. SyntaxNode
class, modifyGetChildren
method to handler properties from type ofSeparatedSyntaxList
Verify the input function
BuiltinFunctions
class, addGetAll
method that return all available functions.Binder
class, modifyBindCallExpression
method:- Check if the input function is right.
- Add some conditions to check if the right parameters was passed.
- Change name of
BindExpression
toBindExpressionInternal
to internal calls BindExpression
method is rewrite, to control functions that can't be void.- modify
BindExpressionStatement
method, to call the newBindExpression
.
- Add more diagnostics to
DiagnosticBag
class.
Apply to repl concept to rewrite and evaluate the right function.
- Create
BoundCallExpression
class, to define call functions. BoundTreeRewriter
class, add new methodRewriteCallExpression
, rewrite all arguments too.Evaluator
class addEvaluateCallExpression
method to eject the correct function.NovaRepl
class, doesn't care null result.
- Add functions to the scope
- Declare functions
BoundScope
class, Add the function concept.
- functions dictionary,
- change
TryDeclare
forTryDeclareVariable
andTryDeclareFunction
- change
TryLookup
forTryLookupVariable
andTryLookupFunction
- Add
GetDeclaredFunctions
method.
Each new submissions should be in nested scope.
Binder
class:
- Refactor 'BindCallExpression' with scope to access to the function
- Create
CreateRootScope
method to look up functions
- Create
Rnd
function inBuiltinFunctions
class, that create a random function. Evaluator
class, evaluate random function.
Create Conversion
class to work with types:
- Identity, that means conversion between the same type.
- Implicit, conversion to an type that we don't have in our language
int To float
. Don't loose data- Explicit,
float To int
. Loose data
- Explicit,
Create Classify
method, that is where define which conversion are available.
Conversion
class has next properties:
- None
- Identity
- Implicit
- Explicit
Binder
class:
- Create
LookupType
method, to match type ("int", "bool", ...) and return theTypeSymbol
of each one. - Modify
BindCallExpression
method to add a condition to match conversion functions - Add
BindConverision
method, to return aBoundConversionExpression
, that is the conversion itself.
BoundTreeRewriter
class, add RewriteConversionExpression
to rewrite the expression.
Evaluator
class create EvaluateConversionExpression
method to match with the correct evaluate conversion.
Bug: Print the last evaluation of the incrementor.
- We will fix it soon ;)
Binder
class:
-
Modify
BindConversion
and create a overcharge of this.- add more condition to avoid cascade errors
- return the same expression if is Identity
-
Modify
BindExpression
method -
Modify
BindAssignmentExpression
method.
You can define the type of the variable that you are declaring.
- Add
:
symbol toLexer
class - Add
ColonToken
concep toSyntaxFacts
class. - Create
TypeClauseSyntax
class. Parser
class:- Modify
ParseVariableDeclaration
to add the type clause. - Add
ParseOptionalTypeClause
andParseTypeClause
methods.
- Modify
- Add
TypeClause
property toVariableDeclarationSyntax
class. Binder
class:- Modify
BindVariableDeclaration
method, to handle type symbols. - Add
BindTypeClause
method that return the type of optional clause. BindConversion
method addallowExplicit
property
- Modify
Are functions that not return values Add functions to global scope concept Add local concept
Create functions
- Create
MemberSyntax
abstract class, that represent whatever you put in the file. - Create
GlobalStatementSyntax
class - Create
ParameterSyntax
class to represent parameters - Create
FunctionDeclarationSyntax
class that contains the definition of complete function.
Apply the function concept:
CompilationUnitSyntax
class, now accept members instead a only statement.NovaRelp
use the last member to complete the submission.SyntaxFacts
class, addFunctionKeyword
- Update
Parser
class to handle functions, parameters and the body. - Update
Binder
class.BindGlobalScope
check for functions into members and try to declare them, after convert the Global statement members into statements.- Add
BindFunctionDeclaration
to check function before declare them.
With this the program already accept functions, but not execute them yet.
Implement execute
behavior at functions.
- Add Global and Locals variables.
- Centralize diagnostics
- Fix tests, etc.
To group all code, move the solution to src
folder
Change nova
project for novai
because this represent the interpreter.
Update Repl
class to ESC
keyword clean the all document instead of the current line.
Update BoundBinaryOperator
table to add ==
and !=
behaviors
- Add basic string test.
Create IO
namespace, and create TextWriterExtensions
handler the output console
- Set up the color to each token.
BoundNode
class now only contain kind
and handles string returns.
Create BoundNodePrinter
class, that handles a fashion way to print each sentences, and centralize the config of output to write trees or labels.
- Output for bound nodes
SyntaxFacts
class add break
and continue
keywords
Parser
class handles break
and continue
tokens
Create break
and continue
statements.
BreakStatementSyntax
ContinueStatementSyntax
To interpret them we need to track of the current loops, use a stack to ensure that binding loops contain can use break
and continue
.
that effective generate the corresponding labels.
Create a stack of Stack<(BoundLabel BreakLabel, BoundLabel ContinueLabel)>
Need report errors during the binding to know if we are able to loop or not.
Binder
class, modify loops:
BindWhileStatement
,BindDoWhileStatement
andBindForStatement
methods, the body generates thebreakLabel
andcontinueLabel
- Add
BindLoopBody
method, to createbreak
andcontinue
labels and the Stack control what number of label is used. - Add
BindBreakStatement
andBindContinueStatement
to return goto statements to able to jump inside of the code block. - Add
BindErrorStatement
method to handler errors.
Create BoundLoopStatement
to abstract keyword labels.
- Modify
BindWhileStatement
,BindDoWhileStatement
andBindForStatement
methods to have breakLabel and continueLabel- This methods inheritance of
BoundLoopStatement
now.
- This methods inheritance of
BoundTreeRewriter
class, add breakLabel
and continueLabel
to loops.
Lowerer
class, uses breakLabel
and continueLabel
labels created to build block of loops.
- while loops block:
while <condition>
<body>
----->
goto continue
body:
<body>
continue:
gotoTrue <condition> body
break:
- Do-while loops block:
do
<body>
while <condition>
----->
body:
<body>
continue:
gotoTrue <condition> body
break:
- For loops block:
for <var> = <lower> to <upper>
<body>
---->
{
var <var> = <lower>
let upperBound = <upper>
while (<var> <= upperBound)
{
<body>
continue:
<var> = <var> + 1
}
}
Create SymbolPrinter
that builds the block symbols to show:
- Output for symbols
- Use
TextWriterExtensions
to write the output
Modify Symbol
class
- Add
WriteTo
method that useSymbolPrinter
. - Modify
ToString
thatWriteTo
the string.
Modify Compilation
class in EmitTree
method:
- Check if there are functions to write them.
- Write header functions and body functions.
The loop condition be re-evaluated after continue. In the following sample:
{
var i = 0
while i < 5
{
i = i + 1
if i == 5
continue
}
print(string(i))
}
was printing 6 as a result, while the equivalent C# would print 5.
-
Lowerer
class, modifyRewriteWhileStatement
andRewriteDoWhileStatement
to addbodyLabel
. -
While loops block:
goto continue
body:
<body>
continue:
gotoTrue <condition> body
break:
endLabel
- Do-while loops block:
body:
<body>
continue:
gotoTrue <condition> body
break:
endLabel
Use SyntaxFacts to get the text to print, it makes use of the SyntaxFacts
class to get the text to print, for the sake of the DRY principle.
TextWriterExtensions
overload methods to useSyntaxFacts
and add a method to write space.- Update
BoundNodePrinter
andSymbolPrinter
to useSyntaxKind
to specific tokens.
- Added tests for exceeding/missing arguments
- Improved error span to something more sensible
- When there are missing or exceeding arguments, highlihgt the missing location (closing parenthesis) or the exceeding tokens, instead of the whole syntax node.
- Report errors for every mismatching argument type in a function call
- Ignore type errors for BoundErrorExpression
- e.g. when the call syntax is
print(x)
andx
is undefined, orprint(,)
- e.g. when the call syntax is
Functions are able to return type.
SyntaxFacts
class addreturn
like a Keyword- Create
ReturnStatementSyntax
class Parser
class, handler return concept and match tokens.
- Create
BoundReturnStatement
class. Binder
class- Delete unsupported report for functions with return type.
- Add
BindReturnStatement
method what controls that there is a function, return statements have an expression and types are matching. DiagnosticBag
have more report forreturn
statements.
BoundTreeRewriter
class addRewriteReturnStatement
method.Evaluator
class handles return types.
Set up class to generate a grapf.dot file