Better formatting and expression handling
This commit is contained in:
@@ -131,6 +131,7 @@ type VariableDefinition struct {
|
||||
Name string
|
||||
TypeExpr string
|
||||
DefaultValue Value
|
||||
IsConst bool
|
||||
}
|
||||
|
||||
func (v *VariableDefinition) Pos() Position { return v.Position }
|
||||
|
||||
@@ -20,6 +20,7 @@ const (
|
||||
TokenBool
|
||||
TokenPackage
|
||||
TokenPragma
|
||||
TokenLet
|
||||
TokenComment
|
||||
TokenDocstring
|
||||
TokenComma
|
||||
@@ -236,7 +237,21 @@ func (l *Lexer) lexString() Token {
|
||||
}
|
||||
|
||||
func (l *Lexer) lexNumber() Token {
|
||||
// Consume initial digits (already started)
|
||||
// Check for hex or binary prefix if we started with '0'
|
||||
if l.input[l.start:l.pos] == "0" {
|
||||
switch l.peek() {
|
||||
case 'x', 'X':
|
||||
l.next()
|
||||
l.lexHexDigits()
|
||||
return l.emit(TokenNumber)
|
||||
case 'b', 'B':
|
||||
l.next()
|
||||
l.lexBinaryDigits()
|
||||
return l.emit(TokenNumber)
|
||||
}
|
||||
}
|
||||
|
||||
// Consume remaining digits
|
||||
l.lexDigits()
|
||||
|
||||
if l.peek() == '.' {
|
||||
@@ -255,6 +270,28 @@ func (l *Lexer) lexNumber() Token {
|
||||
return l.emit(TokenNumber)
|
||||
}
|
||||
|
||||
func (l *Lexer) lexHexDigits() {
|
||||
for {
|
||||
r := l.peek()
|
||||
if unicode.IsDigit(r) || (r >= 'a' && r <= 'f') || (r >= 'A' && r <= 'F') {
|
||||
l.next()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Lexer) lexBinaryDigits() {
|
||||
for {
|
||||
r := l.peek()
|
||||
if r == '0' || r == '1' {
|
||||
l.next()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Lexer) lexDigits() {
|
||||
for unicode.IsDigit(l.peek()) {
|
||||
l.next()
|
||||
@@ -321,6 +358,9 @@ func (l *Lexer) lexHashIdentifier() Token {
|
||||
if val == "#package" {
|
||||
return l.lexUntilNewline(TokenPackage)
|
||||
}
|
||||
if val == "#let" {
|
||||
return l.emit(TokenLet)
|
||||
}
|
||||
return l.emit(TokenIdentifier)
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ func (p *Parser) Parse() (*Configuration, error) {
|
||||
func (p *Parser) parseDefinition() (Definition, bool) {
|
||||
tok := p.next()
|
||||
switch tok.Type {
|
||||
case TokenLet:
|
||||
return p.parseLet(tok)
|
||||
case TokenIdentifier:
|
||||
name := tok.Value
|
||||
if name == "#var" {
|
||||
@@ -286,7 +288,11 @@ func (p *Parser) parseAtom() (Value, bool) {
|
||||
}, true
|
||||
|
||||
case TokenNumber:
|
||||
if strings.Contains(tok.Value, ".") || strings.Contains(tok.Value, "e") {
|
||||
isFloat := (strings.Contains(tok.Value, ".") || strings.Contains(tok.Value, "e") || strings.Contains(tok.Value, "E")) &&
|
||||
!strings.HasPrefix(tok.Value, "0x") && !strings.HasPrefix(tok.Value, "0X") &&
|
||||
!strings.HasPrefix(tok.Value, "0b") && !strings.HasPrefix(tok.Value, "0B")
|
||||
|
||||
if isFloat {
|
||||
f, _ := strconv.ParseFloat(tok.Value, 64)
|
||||
return &FloatValue{Position: tok.Position, Value: f, Raw: tok.Value}, true
|
||||
}
|
||||
@@ -409,6 +415,58 @@ func (p *Parser) parseVariableDefinition(startTok Token) (Definition, bool) {
|
||||
}, true
|
||||
}
|
||||
|
||||
func (p *Parser) parseLet(startTok Token) (Definition, bool) {
|
||||
nameTok := p.next()
|
||||
if nameTok.Type != TokenIdentifier {
|
||||
p.addError(nameTok.Position, "expected constant name")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
if p.next().Type != TokenColon {
|
||||
p.addError(nameTok.Position, "expected :")
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var typeTokens []Token
|
||||
startLine := nameTok.Position.Line
|
||||
|
||||
for {
|
||||
t := p.peek()
|
||||
if t.Position.Line > startLine || t.Type == TokenEOF {
|
||||
break
|
||||
}
|
||||
if t.Type == TokenEqual {
|
||||
break
|
||||
}
|
||||
typeTokens = append(typeTokens, p.next())
|
||||
}
|
||||
|
||||
typeExpr := ""
|
||||
for _, t := range typeTokens {
|
||||
typeExpr += t.Value + " "
|
||||
}
|
||||
|
||||
var defVal Value
|
||||
if p.next().Type != TokenEqual {
|
||||
p.addError(nameTok.Position, "expected =")
|
||||
return nil, false
|
||||
}
|
||||
val, ok := p.parseValue()
|
||||
if ok {
|
||||
defVal = val
|
||||
} else {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &VariableDefinition{
|
||||
Position: startTok.Position,
|
||||
Name: nameTok.Value,
|
||||
TypeExpr: strings.TrimSpace(typeExpr),
|
||||
DefaultValue: defVal,
|
||||
IsConst: true,
|
||||
}, true
|
||||
}
|
||||
|
||||
func (p *Parser) Errors() []error {
|
||||
return p.errors
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user