init
This commit is contained in:
commit
8f4f858d86
30 changed files with 9765 additions and 0 deletions
235
internal/lang/ast.go
Normal file
235
internal/lang/ast.go
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
package lang
|
||||
|
||||
type Program struct {
|
||||
PackagePath string
|
||||
Imports []ImportDecl
|
||||
Interfaces []InterfaceDecl
|
||||
Classes []ClassDecl
|
||||
Workers []WorkerDecl
|
||||
Functions []FunctionDecl
|
||||
}
|
||||
|
||||
type ImportDecl struct {
|
||||
Alias string
|
||||
Path string
|
||||
}
|
||||
|
||||
type InterfaceDecl struct {
|
||||
Name string
|
||||
Methods []FunctionSignature
|
||||
}
|
||||
|
||||
type ClassDecl struct {
|
||||
Name string
|
||||
Fields []FieldDecl
|
||||
Parents []string
|
||||
Methods []FunctionDecl
|
||||
}
|
||||
|
||||
type WorkerDecl struct {
|
||||
Name string
|
||||
Fields []WorkerFieldDecl
|
||||
Methods []FunctionDecl
|
||||
}
|
||||
|
||||
type WorkerFieldDecl struct {
|
||||
Mutable bool
|
||||
Name string
|
||||
Type string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
type FieldDecl struct {
|
||||
Mutable bool
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
type FunctionSignature struct {
|
||||
Name string
|
||||
Params []Param
|
||||
ReturnType string
|
||||
}
|
||||
|
||||
type FunctionDecl struct {
|
||||
Name string
|
||||
Params []Param
|
||||
ReturnType string
|
||||
Body []Stmt
|
||||
}
|
||||
|
||||
type Param struct {
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
type Stmt interface {
|
||||
stmtNode()
|
||||
}
|
||||
|
||||
type Expr interface {
|
||||
exprNode()
|
||||
}
|
||||
|
||||
type VarDecl struct {
|
||||
Mutable bool
|
||||
Name string
|
||||
Type string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (VarDecl) stmtNode() {}
|
||||
|
||||
type MultiVarDecl struct {
|
||||
Mutable bool
|
||||
Names []string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (MultiVarDecl) stmtNode() {}
|
||||
|
||||
type AssignStmt struct {
|
||||
Name string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (AssignStmt) stmtNode() {}
|
||||
|
||||
type AddAssignStmt struct {
|
||||
Name string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (AddAssignStmt) stmtNode() {}
|
||||
|
||||
type MultiAssignStmt struct {
|
||||
Names []string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (MultiAssignStmt) stmtNode() {}
|
||||
|
||||
type ReturnStmt struct {
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (ReturnStmt) stmtNode() {}
|
||||
|
||||
type ThrowStmt struct {
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (ThrowStmt) stmtNode() {}
|
||||
|
||||
type GoStmt struct {
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (GoStmt) stmtNode() {}
|
||||
|
||||
type ExprStmt struct {
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (ExprStmt) stmtNode() {}
|
||||
|
||||
type IfStmt struct {
|
||||
Cond Expr
|
||||
Then []Stmt
|
||||
Else []Stmt
|
||||
}
|
||||
|
||||
func (IfStmt) stmtNode() {}
|
||||
|
||||
type WhileStmt struct {
|
||||
Cond Expr
|
||||
Body []Stmt
|
||||
}
|
||||
|
||||
func (WhileStmt) stmtNode() {}
|
||||
|
||||
type TryCatchStmt struct {
|
||||
TryBody []Stmt
|
||||
CatchName string
|
||||
CatchType string
|
||||
CatchBody []Stmt
|
||||
}
|
||||
|
||||
func (TryCatchStmt) stmtNode() {}
|
||||
|
||||
type SelectStmt struct {
|
||||
Cases []SelectCase
|
||||
}
|
||||
|
||||
func (SelectStmt) stmtNode() {}
|
||||
|
||||
type SelectCase struct {
|
||||
Source Expr
|
||||
Body []Stmt
|
||||
}
|
||||
|
||||
type IdentExpr struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (IdentExpr) exprNode() {}
|
||||
|
||||
type IntExpr struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (IntExpr) exprNode() {}
|
||||
|
||||
type StringExpr struct {
|
||||
Value string
|
||||
}
|
||||
|
||||
func (StringExpr) exprNode() {}
|
||||
|
||||
type BoolExpr struct {
|
||||
Value bool
|
||||
}
|
||||
|
||||
func (BoolExpr) exprNode() {}
|
||||
|
||||
type NullExpr struct{}
|
||||
|
||||
func (NullExpr) exprNode() {}
|
||||
|
||||
type UnaryExpr struct {
|
||||
Op string
|
||||
Value Expr
|
||||
}
|
||||
|
||||
func (UnaryExpr) exprNode() {}
|
||||
|
||||
type BinaryExpr struct {
|
||||
Left Expr
|
||||
Op string
|
||||
Right Expr
|
||||
}
|
||||
|
||||
func (BinaryExpr) exprNode() {}
|
||||
|
||||
type CallExpr struct {
|
||||
Callee Expr
|
||||
Args []Expr
|
||||
TypeArgs []string
|
||||
}
|
||||
|
||||
func (CallExpr) exprNode() {}
|
||||
|
||||
type SelectorExpr struct {
|
||||
Receiver Expr
|
||||
Name string
|
||||
}
|
||||
|
||||
func (SelectorExpr) exprNode() {}
|
||||
|
||||
type LambdaExpr struct {
|
||||
Params []Param
|
||||
ImplicitIt bool
|
||||
Body []Stmt
|
||||
}
|
||||
|
||||
func (LambdaExpr) exprNode() {}
|
||||
1189
internal/lang/compiler_test.go
Normal file
1189
internal/lang/compiler_test.go
Normal file
File diff suppressed because it is too large
Load diff
2507
internal/lang/generate_go.go
Normal file
2507
internal/lang/generate_go.go
Normal file
File diff suppressed because it is too large
Load diff
167
internal/lang/lexer.go
Normal file
167
internal/lang/lexer.go
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
package lang
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type lexer struct {
|
||||
src []rune
|
||||
pos int
|
||||
}
|
||||
|
||||
func lex(input string) ([]token, error) {
|
||||
l := &lexer{src: []rune(input)}
|
||||
var tokens []token
|
||||
for {
|
||||
tok, err := l.next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokens = append(tokens, tok)
|
||||
if tok.kind == tokenEOF {
|
||||
return tokens, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) next() (token, error) {
|
||||
l.skipWhitespace()
|
||||
start := l.pos
|
||||
if l.pos >= len(l.src) {
|
||||
return token{kind: tokenEOF, pos: start}, nil
|
||||
}
|
||||
|
||||
ch := l.src[l.pos]
|
||||
switch {
|
||||
case isIdentStart(ch):
|
||||
l.pos++
|
||||
for l.pos < len(l.src) && isIdentPart(l.src[l.pos]) {
|
||||
l.pos++
|
||||
}
|
||||
lexeme := string(l.src[start:l.pos])
|
||||
if kind, ok := keywords[lexeme]; ok {
|
||||
return token{kind: kind, lexeme: lexeme, pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenIdent, lexeme: lexeme, pos: start}, nil
|
||||
case unicode.IsDigit(ch):
|
||||
l.pos++
|
||||
for l.pos < len(l.src) && unicode.IsDigit(l.src[l.pos]) {
|
||||
l.pos++
|
||||
}
|
||||
return token{kind: tokenInt, lexeme: string(l.src[start:l.pos]), pos: start}, nil
|
||||
case ch == '"':
|
||||
l.pos++
|
||||
for l.pos < len(l.src) && l.src[l.pos] != '"' {
|
||||
if l.src[l.pos] == '\\' {
|
||||
l.pos++
|
||||
if l.pos >= len(l.src) {
|
||||
return token{}, fmt.Errorf("unterminated string at %d", start)
|
||||
}
|
||||
}
|
||||
l.pos++
|
||||
}
|
||||
if l.pos >= len(l.src) {
|
||||
return token{}, fmt.Errorf("unterminated string at %d", start)
|
||||
}
|
||||
l.pos++
|
||||
return token{kind: tokenString, lexeme: string(l.src[start:l.pos]), pos: start}, nil
|
||||
default:
|
||||
l.pos++
|
||||
switch ch {
|
||||
case '(':
|
||||
return token{kind: tokenLParen, lexeme: "(", pos: start}, nil
|
||||
case ')':
|
||||
return token{kind: tokenRParen, lexeme: ")", pos: start}, nil
|
||||
case '{':
|
||||
return token{kind: tokenLBrace, lexeme: "{", pos: start}, nil
|
||||
case '}':
|
||||
return token{kind: tokenRBrace, lexeme: "}", pos: start}, nil
|
||||
case ',':
|
||||
return token{kind: tokenComma, lexeme: ",", pos: start}, nil
|
||||
case '.':
|
||||
return token{kind: tokenDot, lexeme: ".", pos: start}, nil
|
||||
case ':':
|
||||
return token{kind: tokenColon, lexeme: ":", pos: start}, nil
|
||||
case ';':
|
||||
return token{kind: tokenSemicolon, lexeme: ";", pos: start}, nil
|
||||
case '+':
|
||||
if l.match('=') {
|
||||
return token{kind: tokenPlusAssign, lexeme: "+=", pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenPlus, lexeme: "+", pos: start}, nil
|
||||
case '-':
|
||||
if l.match('>') {
|
||||
return token{kind: tokenArrow, lexeme: "->", pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenMinus, lexeme: "-", pos: start}, nil
|
||||
case '*':
|
||||
return token{kind: tokenStar, lexeme: "*", pos: start}, nil
|
||||
case '/':
|
||||
if l.match('/') {
|
||||
for l.pos < len(l.src) && l.src[l.pos] != '\n' {
|
||||
l.pos++
|
||||
}
|
||||
return l.next()
|
||||
}
|
||||
return token{kind: tokenSlash, lexeme: "/", pos: start}, nil
|
||||
case '%':
|
||||
return token{kind: tokenPercent, lexeme: "%", pos: start}, nil
|
||||
case '!':
|
||||
if l.match('=') {
|
||||
return token{kind: tokenNeq, lexeme: "!=", pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenBang, lexeme: "!", pos: start}, nil
|
||||
case '=':
|
||||
if l.match('=') {
|
||||
return token{kind: tokenEq, lexeme: "==", pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenAssign, lexeme: "=", pos: start}, nil
|
||||
case '<':
|
||||
if l.match('=') {
|
||||
return token{kind: tokenLte, lexeme: "<=", pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenLt, lexeme: "<", pos: start}, nil
|
||||
case '>':
|
||||
if l.match('=') {
|
||||
return token{kind: tokenGte, lexeme: ">=", pos: start}, nil
|
||||
}
|
||||
return token{kind: tokenGt, lexeme: ">", pos: start}, nil
|
||||
case '&':
|
||||
if l.match('&') {
|
||||
return token{kind: tokenAnd, lexeme: "&&", pos: start}, nil
|
||||
}
|
||||
case '|':
|
||||
if l.match('|') {
|
||||
return token{kind: tokenOr, lexeme: "||", pos: start}, nil
|
||||
}
|
||||
}
|
||||
return token{}, fmt.Errorf("unexpected character %q at %d", ch, start)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *lexer) match(expected rune) bool {
|
||||
if l.pos >= len(l.src) || l.src[l.pos] != expected {
|
||||
return false
|
||||
}
|
||||
l.pos++
|
||||
return true
|
||||
}
|
||||
|
||||
func (l *lexer) skipWhitespace() {
|
||||
for l.pos < len(l.src) {
|
||||
if unicode.IsSpace(l.src[l.pos]) {
|
||||
l.pos++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func isIdentStart(ch rune) bool {
|
||||
return unicode.IsLetter(ch) || ch == '_'
|
||||
}
|
||||
|
||||
func isIdentPart(ch rune) bool {
|
||||
return isIdentStart(ch) || unicode.IsDigit(ch)
|
||||
}
|
||||
1056
internal/lang/parser.go
Normal file
1056
internal/lang/parser.go
Normal file
File diff suppressed because it is too large
Load diff
86
internal/lang/token.go
Normal file
86
internal/lang/token.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package lang
|
||||
|
||||
type tokenKind string
|
||||
|
||||
const (
|
||||
tokenEOF tokenKind = "EOF"
|
||||
tokenIdent tokenKind = "IDENT"
|
||||
tokenInt tokenKind = "INT"
|
||||
tokenString tokenKind = "STRING"
|
||||
tokenTrue tokenKind = "TRUE"
|
||||
tokenFalse tokenKind = "FALSE"
|
||||
tokenNull tokenKind = "NULL"
|
||||
tokenImport tokenKind = "IMPORT"
|
||||
tokenPackage tokenKind = "PACKAGE"
|
||||
tokenClass tokenKind = "CLASS"
|
||||
tokenWorker tokenKind = "WORKER"
|
||||
tokenInterface tokenKind = "INTERFACE"
|
||||
tokenFun tokenKind = "FUN"
|
||||
tokenOverride tokenKind = "OVERRIDE"
|
||||
tokenVal tokenKind = "VAL"
|
||||
tokenVar tokenKind = "VAR"
|
||||
tokenIf tokenKind = "IF"
|
||||
tokenElse tokenKind = "ELSE"
|
||||
tokenWhile tokenKind = "WHILE"
|
||||
tokenSelect tokenKind = "SELECT"
|
||||
tokenReturn tokenKind = "RETURN"
|
||||
tokenGo tokenKind = "GO"
|
||||
tokenTry tokenKind = "TRY"
|
||||
tokenCatch tokenKind = "CATCH"
|
||||
tokenThrow tokenKind = "THROW"
|
||||
tokenLParen tokenKind = "("
|
||||
tokenRParen tokenKind = ")"
|
||||
tokenLBrace tokenKind = "{"
|
||||
tokenRBrace tokenKind = "}"
|
||||
tokenComma tokenKind = ","
|
||||
tokenDot tokenKind = "."
|
||||
tokenColon tokenKind = ":"
|
||||
tokenSemicolon tokenKind = ";"
|
||||
tokenPlus tokenKind = "+"
|
||||
tokenMinus tokenKind = "-"
|
||||
tokenStar tokenKind = "*"
|
||||
tokenSlash tokenKind = "/"
|
||||
tokenPercent tokenKind = "%"
|
||||
tokenBang tokenKind = "!"
|
||||
tokenAssign tokenKind = "="
|
||||
tokenPlusAssign tokenKind = "+="
|
||||
tokenEq tokenKind = "=="
|
||||
tokenNeq tokenKind = "!="
|
||||
tokenLt tokenKind = "<"
|
||||
tokenLte tokenKind = "<="
|
||||
tokenGt tokenKind = ">"
|
||||
tokenGte tokenKind = ">="
|
||||
tokenAnd tokenKind = "&&"
|
||||
tokenOr tokenKind = "||"
|
||||
tokenArrow tokenKind = "->"
|
||||
)
|
||||
|
||||
var keywords = map[string]tokenKind{
|
||||
"fun": tokenFun,
|
||||
"import": tokenImport,
|
||||
"package": tokenPackage,
|
||||
"class": tokenClass,
|
||||
"worker": tokenWorker,
|
||||
"interface": tokenInterface,
|
||||
"val": tokenVal,
|
||||
"var": tokenVar,
|
||||
"override": tokenOverride,
|
||||
"if": tokenIf,
|
||||
"else": tokenElse,
|
||||
"while": tokenWhile,
|
||||
"select": tokenSelect,
|
||||
"return": tokenReturn,
|
||||
"go": tokenGo,
|
||||
"try": tokenTry,
|
||||
"catch": tokenCatch,
|
||||
"throw": tokenThrow,
|
||||
"true": tokenTrue,
|
||||
"false": tokenFalse,
|
||||
"null": tokenNull,
|
||||
}
|
||||
|
||||
type token struct {
|
||||
kind tokenKind
|
||||
lexeme string
|
||||
pos int
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue