Skip to content

Commit

Permalink
add support for scientific notation for digits
Browse files Browse the repository at this point in the history
  • Loading branch information
gravataLonga committed Aug 2, 2022
1 parent 343f184 commit 15e26cf
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 9 deletions.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,21 @@ puts(a);
100.20;
5.20;
/**
* Scientific Notation
*/
1e3;
2e-3;
/**
* Strings
*/
"hello"
"hello \t world \x02\x03"
"\u006E\u0069\u006E\u006A\u0061" // ninja in unicode chars
"\n\r\t\b\f" // special caracters is also supported
/**
* array
Expand Down
16 changes: 16 additions & 0 deletions evaluator/digit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ func TestEvalDigitExpression(t *testing.T) {
input string
expected interface{}
}{
{
`1`,
1,
},
{
`0.2`,
0.2,
},
{
`1e3`,
1e3,
},
{
`1e-3`,
1e-3,
},
{
`1 + 1`,
2,
Expand Down
25 changes: 23 additions & 2 deletions lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ func isDigit(ch byte) bool {
return '0' <= ch && ch <= '9'
}

func isScientificNotation(ch byte) bool {
return ch == 'e' || ch == 'E'
}

func (l *Lexer) readIdentifier() []byte {
position := l.position
for isLetter(l.ch) || isDigit(l.ch) {
Expand All @@ -201,8 +205,25 @@ func (l *Lexer) readIdentifier() []byte {
// readDigit read integer and floats
func (l *Lexer) readDigit() []byte {
position := l.position
for isDigit(l.ch) || (l.ch == '.' && isDigit(l.peekChar())) || (l.ch == 'e' && isDigit(l.peekChar())) {
l.readChar()
isOnScientificNotation := false

for {
if isDigit(l.ch) || (l.ch == '.' && isDigit(l.peekChar())) {
l.readChar()
continue
}

if l.ch == '-' && isOnScientificNotation {
l.readChar()
continue
}

if isScientificNotation(l.ch) && !isOnScientificNotation {
isOnScientificNotation = true
l.readChar()
continue
}
break
}
return []byte(l.input[position:l.position])
}
Expand Down
12 changes: 11 additions & 1 deletion lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ func TestLexerReadNumber(t *testing.T) {
`1`,
token.INT,
},
{
`2`,
`2`,
token.INT,
},
{
`1234`,
`1234`,
Expand All @@ -267,7 +272,12 @@ func TestLexerReadNumber(t *testing.T) {
{
`1e3`,
`1e3`,
token.INT,
token.FLOAT,
},
{
`1e-3`,
`1e-3`,
token.FLOAT,
},
}

Expand Down
2 changes: 1 addition & 1 deletion parser/infix.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "github.com/gravataLonga/ninja/ast"
func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression {
expression := &ast.InfixExpression{
Token: p.curToken,
Operator: string(p.curToken.Literal),
Operator: p.curToken.Literal,
Left: left,
}

Expand Down
2 changes: 1 addition & 1 deletion parser/integer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
func (p *Parser) parseIntegerLiteral() ast.Expression {
lit := &ast.IntegerLiteral{Token: p.curToken}

value, err := strconv.ParseInt(string(p.curToken.Literal), 0, 64)
value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
if err != nil {
p.newError("could not parse %q as integer", p.curToken.Literal)
return nil
Expand Down
2 changes: 1 addition & 1 deletion parser/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package parser
import "github.com/gravataLonga/ninja/ast"

func (p *Parser) parseString() ast.Expression {
return &ast.StringLiteral{Token: p.curToken, Value: string(p.curToken.Literal)}
return &ast.StringLiteral{Token: p.curToken, Value: p.curToken.Literal}
}
5 changes: 3 additions & 2 deletions token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,9 @@ func LookupIdentifier(ident []byte) TokenType {
// for now we only support integer and float, but later we
// need to support Hex and Octa. @todo
func DigitType(digit []byte) TokenType {
hasDot := bytes.IndexByte(digit, '.')
if hasDot >= 0 {
hasDot := bytes.IndexByte(digit, '.') >= 0
hasENotation := bytes.IndexByte(digit, 'e') >= 0 || bytes.IndexByte(digit, 'E') >= 0
if hasDot || hasENotation {
return FLOAT
}
return INT
Expand Down

0 comments on commit 15e26cf

Please sign in to comment.