Improved performance
This commit is contained in:
parent
3c70529015
commit
778c125d19
@ -11,8 +11,8 @@ import (
|
|||||||
// Compile waits for the scan to finish and compiles all functions.
|
// Compile waits for the scan to finish and compiles all functions.
|
||||||
func Compile(files <-chan *fs.File, functions <-chan *core.Function, errs <-chan error) (Result, error) {
|
func Compile(files <-chan *fs.File, functions <-chan *core.Function, errs <-chan error) (Result, error) {
|
||||||
result := Result{}
|
result := Result{}
|
||||||
|
allFiles := make([]*fs.File, 0, 8)
|
||||||
allFunctions := map[string]*core.Function{}
|
allFunctions := map[string]*core.Function{}
|
||||||
allFiles := map[string]*fs.File{}
|
|
||||||
|
|
||||||
for functions != nil || files != nil || errs != nil {
|
for functions != nil || files != nil || errs != nil {
|
||||||
select {
|
select {
|
||||||
@ -31,7 +31,7 @@ func Compile(files <-chan *fs.File, functions <-chan *core.Function, errs <-chan
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
allFiles[file.Path] = file
|
allFiles = append(allFiles, file)
|
||||||
|
|
||||||
case err, ok := <-errs:
|
case err, ok := <-errs:
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -23,7 +23,4 @@ var (
|
|||||||
|
|
||||||
// Skips writing the executable to disk.
|
// Skips writing the executable to disk.
|
||||||
Dry = false
|
Dry = false
|
||||||
|
|
||||||
// Skips compiling assert statements.
|
|
||||||
SkipAsserts = false
|
|
||||||
)
|
)
|
||||||
|
@ -5,15 +5,10 @@ import (
|
|||||||
|
|
||||||
"git.akyoto.dev/cli/q/src/build/asm"
|
"git.akyoto.dev/cli/q/src/build/asm"
|
||||||
"git.akyoto.dev/cli/q/src/build/ast"
|
"git.akyoto.dev/cli/q/src/build/ast"
|
||||||
"git.akyoto.dev/cli/q/src/build/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CompileAssert compiles an assertion.
|
// CompileAssert compiles an assertion.
|
||||||
func (f *Function) CompileAssert(assert *ast.Assert) error {
|
func (f *Function) CompileAssert(assert *ast.Assert) error {
|
||||||
if config.SkipAsserts {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f.count.assert++
|
f.count.assert++
|
||||||
success := fmt.Sprintf("%s_assert_%d_true", f.Name, f.count.assert)
|
success := fmt.Sprintf("%s_assert_%d_true", f.Name, f.count.assert)
|
||||||
fail := fmt.Sprintf("%s_assert_%d_false", f.Name, f.count.assert)
|
fail := fmt.Sprintf("%s_assert_%d_false", f.Name, f.count.assert)
|
||||||
|
@ -15,7 +15,7 @@ type Operator struct {
|
|||||||
|
|
||||||
// Operators defines the operators used in the language.
|
// Operators defines the operators used in the language.
|
||||||
// The number corresponds to the operator priority and can not be zero.
|
// The number corresponds to the operator priority and can not be zero.
|
||||||
var Operators = map[token.Kind]*Operator{
|
var Operators = [64]Operator{
|
||||||
token.Period: {".", 13, 2},
|
token.Period: {".", 13, 2},
|
||||||
token.Call: {"λ", 12, 1},
|
token.Call: {"λ", 12, 1},
|
||||||
token.Array: {"@", 12, 2},
|
token.Array: {"@", 12, 2},
|
||||||
@ -41,12 +41,15 @@ var Operators = map[token.Kind]*Operator{
|
|||||||
token.LogicalAnd: {"&&", 2, 2},
|
token.LogicalAnd: {"&&", 2, 2},
|
||||||
token.LogicalOr: {"||", 1, 2},
|
token.LogicalOr: {"||", 1, 2},
|
||||||
|
|
||||||
|
token.Separator: {",", 0, 2},
|
||||||
|
|
||||||
token.Assign: {"=", math.MinInt8, 2},
|
token.Assign: {"=", math.MinInt8, 2},
|
||||||
token.Define: {":=", math.MinInt8, 2},
|
token.Define: {":=", math.MinInt8, 2},
|
||||||
token.AddAssign: {"+=", math.MinInt8, 2},
|
token.AddAssign: {"+=", math.MinInt8, 2},
|
||||||
token.SubAssign: {"-=", math.MinInt8, 2},
|
token.SubAssign: {"-=", math.MinInt8, 2},
|
||||||
token.MulAssign: {"*=", math.MinInt8, 2},
|
token.MulAssign: {"*=", math.MinInt8, 2},
|
||||||
token.DivAssign: {"/=", math.MinInt8, 2},
|
token.DivAssign: {"/=", math.MinInt8, 2},
|
||||||
|
token.ModAssign: {"%=", math.MinInt8, 2},
|
||||||
token.ShrAssign: {">>=", math.MinInt8, 2},
|
token.ShrAssign: {">>=", math.MinInt8, 2},
|
||||||
token.ShlAssign: {"<<=", math.MinInt8, 2},
|
token.ShlAssign: {"<<=", math.MinInt8, 2},
|
||||||
}
|
}
|
||||||
@ -68,21 +71,9 @@ func isComplete(expr *Expression) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func numOperands(symbol token.Kind) int {
|
func numOperands(symbol token.Kind) int {
|
||||||
operator, exists := Operators[symbol]
|
return int(Operators[symbol].Operands)
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(operator.Operands)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func precedence(symbol token.Kind) int8 {
|
func precedence(symbol token.Kind) int8 {
|
||||||
operator, exists := Operators[symbol]
|
return Operators[symbol].Precedence
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return operator.Precedence
|
|
||||||
}
|
}
|
||||||
|
@ -101,63 +101,64 @@ func Parse(tokens []token.Token) *Expression {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.IsOperator() {
|
if !t.IsOperator() {
|
||||||
if cursor == nil {
|
|
||||||
cursor = NewLeaf(t)
|
|
||||||
cursor.Precedence = precedence(t.Kind)
|
|
||||||
root = cursor
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
node := NewLeaf(t)
|
|
||||||
node.Precedence = precedence(t.Kind)
|
|
||||||
|
|
||||||
if cursor.Token.IsOperator() {
|
|
||||||
oldPrecedence := cursor.Precedence
|
|
||||||
newPrecedence := node.Precedence
|
|
||||||
|
|
||||||
if newPrecedence > oldPrecedence {
|
|
||||||
if len(cursor.Children) == numOperands(cursor.Token.Kind) {
|
|
||||||
cursor.LastChild().Replace(node)
|
|
||||||
} else {
|
|
||||||
cursor.AddChild(node)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
start := cursor
|
|
||||||
|
|
||||||
for start != nil {
|
|
||||||
precedence := start.Precedence
|
|
||||||
|
|
||||||
if precedence < newPrecedence {
|
|
||||||
start.LastChild().Replace(node)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if precedence == newPrecedence {
|
|
||||||
if start == root {
|
|
||||||
root = node
|
|
||||||
}
|
|
||||||
|
|
||||||
start.Replace(node)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
start = start.Parent
|
|
||||||
}
|
|
||||||
|
|
||||||
if start == nil {
|
|
||||||
root.Replace(node)
|
|
||||||
root = node
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
node.AddChild(cursor)
|
|
||||||
root = node
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = node
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor == nil {
|
||||||
|
cursor = NewLeaf(t)
|
||||||
|
cursor.Precedence = precedence(t.Kind)
|
||||||
|
root = cursor
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
node := NewLeaf(t)
|
||||||
|
node.Precedence = precedence(t.Kind)
|
||||||
|
|
||||||
|
if cursor.Token.IsOperator() {
|
||||||
|
oldPrecedence := cursor.Precedence
|
||||||
|
newPrecedence := node.Precedence
|
||||||
|
|
||||||
|
if newPrecedence > oldPrecedence {
|
||||||
|
if len(cursor.Children) == numOperands(cursor.Token.Kind) {
|
||||||
|
cursor.LastChild().Replace(node)
|
||||||
|
} else {
|
||||||
|
cursor.AddChild(node)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
start := cursor
|
||||||
|
|
||||||
|
for start != nil {
|
||||||
|
precedence := start.Precedence
|
||||||
|
|
||||||
|
if precedence < newPrecedence {
|
||||||
|
start.LastChild().Replace(node)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if precedence == newPrecedence {
|
||||||
|
if start == root {
|
||||||
|
root = node
|
||||||
|
}
|
||||||
|
|
||||||
|
start.Replace(node)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
start = start.Parent
|
||||||
|
}
|
||||||
|
|
||||||
|
if start == nil {
|
||||||
|
root.Replace(node)
|
||||||
|
root = node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.AddChild(cursor)
|
||||||
|
root = node
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = node
|
||||||
}
|
}
|
||||||
|
|
||||||
return root
|
return root
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"git.akyoto.dev/cli/q/src/build/token"
|
"git.akyoto.dev/cli/q/src/build/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Stack is a stack of scopes.
|
||||||
type Stack struct {
|
type Stack struct {
|
||||||
Scopes []*Scope
|
Scopes []*Scope
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,6 @@ const (
|
|||||||
BlockEnd // }
|
BlockEnd // }
|
||||||
ArrayStart // [
|
ArrayStart // [
|
||||||
ArrayEnd // ]
|
ArrayEnd // ]
|
||||||
_keywords // <keywords>
|
|
||||||
Assert // assert
|
|
||||||
Else // else
|
|
||||||
If // if
|
|
||||||
Import // import
|
|
||||||
Loop // loop
|
|
||||||
Return // return
|
|
||||||
_keywordsEnd // </keywords>
|
|
||||||
_operators // <operators>
|
_operators // <operators>
|
||||||
Add // +
|
Add // +
|
||||||
Sub // -
|
Sub // -
|
||||||
@ -68,4 +60,12 @@ const (
|
|||||||
ShrAssign // >>=
|
ShrAssign // >>=
|
||||||
_assignmentsEnd // </assignments>
|
_assignmentsEnd // </assignments>
|
||||||
_operatorsEnd // </operators>
|
_operatorsEnd // </operators>
|
||||||
|
_keywords // <keywords>
|
||||||
|
Assert // assert
|
||||||
|
Else // else
|
||||||
|
If // if
|
||||||
|
Import // import
|
||||||
|
Loop // loop
|
||||||
|
Return // return
|
||||||
|
_keywordsEnd // </keywords>
|
||||||
)
|
)
|
||||||
|
@ -25,11 +25,15 @@ func TestFunction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestKeyword(t *testing.T) {
|
func TestKeyword(t *testing.T) {
|
||||||
tokens := token.Tokenize([]byte("return x"))
|
tokens := token.Tokenize([]byte("assert if import else loop return"))
|
||||||
|
|
||||||
expected := []token.Kind{
|
expected := []token.Kind{
|
||||||
|
token.Assert,
|
||||||
|
token.If,
|
||||||
|
token.Import,
|
||||||
|
token.Else,
|
||||||
|
token.Loop,
|
||||||
token.Return,
|
token.Return,
|
||||||
token.Identifier,
|
|
||||||
token.EOF,
|
token.EOF,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,6 +107,37 @@ func TestOperator(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOperatorAssign(t *testing.T) {
|
||||||
|
tokens := token.Tokenize([]byte(`a += b -= c *= d /= e &= f |= g ^= h <<= i >>= j`))
|
||||||
|
|
||||||
|
expected := []token.Kind{
|
||||||
|
token.Identifier,
|
||||||
|
token.AddAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.SubAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.MulAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.DivAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.AndAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.OrAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.XorAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.ShlAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.ShrAssign,
|
||||||
|
token.Identifier,
|
||||||
|
token.EOF,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, kind := range expected {
|
||||||
|
assert.Equal(t, tokens[i].Kind, kind)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNegateFirstToken(t *testing.T) {
|
func TestNegateFirstToken(t *testing.T) {
|
||||||
tokens := token.Tokenize([]byte(`-a`))
|
tokens := token.Tokenize([]byte(`-a`))
|
||||||
|
|
||||||
@ -244,37 +279,6 @@ func TestLeadingZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOperatorAssign(t *testing.T) {
|
|
||||||
tokens := token.Tokenize([]byte(`a += b -= c *= d /= e &= f |= g ^= h <<= i >>= j`))
|
|
||||||
|
|
||||||
expected := []token.Kind{
|
|
||||||
token.Identifier,
|
|
||||||
token.AddAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.SubAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.MulAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.DivAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.AndAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.OrAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.XorAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.ShlAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.ShrAssign,
|
|
||||||
token.Identifier,
|
|
||||||
token.EOF,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, kind := range expected {
|
|
||||||
assert.Equal(t, tokens[i].Kind, kind)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSeparator(t *testing.T) {
|
func TestSeparator(t *testing.T) {
|
||||||
tokens := token.Tokenize([]byte("a,b,c"))
|
tokens := token.Tokenize([]byte("a,b,c"))
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ func Run(args []string) int {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
|
||||||
switch err.(type) {
|
switch err := err.(type) {
|
||||||
case *exec.ExitError:
|
case *exec.ExitError:
|
||||||
return 0
|
return err.ExitCode()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 1
|
return 1
|
||||||
|
@ -18,6 +18,5 @@ func System(args []string) int {
|
|||||||
fmt.Printf(line, "Compiler:", config.Executable)
|
fmt.Printf(line, "Compiler:", config.Executable)
|
||||||
fmt.Printf(line, "Library:", config.Library)
|
fmt.Printf(line, "Library:", config.Library)
|
||||||
fmt.Printf(line, "Threads:", strconv.Itoa(runtime.NumCPU()))
|
fmt.Printf(line, "Threads:", strconv.Itoa(runtime.NumCPU()))
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user