This commit is contained in:
parent
adfcd4b60c
commit
9b51680af5
8 changed files with 202 additions and 0 deletions
5
lib/io/write.q
Normal file
5
lib/io/write.q
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
write(buffer []byte) -> int {
|
||||||
|
return os.write(0, buffer, len(buffer))
|
||||||
|
}
|
3
lib/os/os_linux.q
Normal file
3
lib/os/os_linux.q
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
write(fd int, buffer *byte, length int) -> int {
|
||||||
|
return syscall(1, fd, buffer, length)
|
||||||
|
}
|
11
src/errors/String.go
Normal file
11
src/errors/String.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
// String is used for static errors that have no parameters.
|
||||||
|
type String struct {
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (err *String) Error() string {
|
||||||
|
return err.Message
|
||||||
|
}
|
69
src/global/global.go
Normal file
69
src/global/global.go
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package global
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime/debug"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Global variables that are useful in all packages.
|
||||||
|
var (
|
||||||
|
Executable string
|
||||||
|
Library string
|
||||||
|
Root string
|
||||||
|
WorkingDirectory string
|
||||||
|
)
|
||||||
|
|
||||||
|
// init is the very first thing that's executed.
|
||||||
|
// It disables the GC and initializes global variables.
|
||||||
|
func init() {
|
||||||
|
debug.SetGCPercent(-1)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
Executable, err = os.Executable()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Executable, err = filepath.EvalSymlinks(Executable)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkingDirectory, err = os.Getwd()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
Root = filepath.Dir(Executable)
|
||||||
|
Library = filepath.Join(Root, "lib")
|
||||||
|
stat, err := os.Stat(Library)
|
||||||
|
|
||||||
|
if err != nil || !stat.IsDir() {
|
||||||
|
findLibrary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// findLibrary tries to go up each directory from the working directory and check for the existence of a "lib" directory.
|
||||||
|
// This is needed for tests to work correctly.
|
||||||
|
func findLibrary() {
|
||||||
|
dir := WorkingDirectory
|
||||||
|
|
||||||
|
for {
|
||||||
|
Library = filepath.Join(dir, "lib")
|
||||||
|
stat, err := os.Stat(Library)
|
||||||
|
|
||||||
|
if err == nil && stat.IsDir() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir == "/" {
|
||||||
|
panic("standard library not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
dir = filepath.Dir(dir)
|
||||||
|
}
|
||||||
|
}
|
41
src/scanner/errors.go
Normal file
41
src/scanner/errors.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
expectedPackageName = &errors.String{Message: "Expected package name"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// invalidCharacter is created when an invalid character appears.
|
||||||
|
type invalidCharacter struct {
|
||||||
|
Character string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (err *invalidCharacter) Error() string {
|
||||||
|
return fmt.Sprintf("Invalid character '%s'", err.Character)
|
||||||
|
}
|
||||||
|
|
||||||
|
// invalidTopLevel error is created when a top-level instruction is not valid.
|
||||||
|
type invalidTopLevel struct {
|
||||||
|
Instruction string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error generates the string representation.
|
||||||
|
func (err *invalidTopLevel) Error() string {
|
||||||
|
return fmt.Sprintf("Invalid top level instruction '%s'", err.Instruction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isNotDirectory error is created when a path is not a directory.
|
||||||
|
type isNotDirectory struct {
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error generates the string representation.
|
||||||
|
func (err *isNotDirectory) Error() string {
|
||||||
|
return fmt.Sprintf("Import path '%s' is not a directory", err.Path)
|
||||||
|
}
|
15
src/scanner/scanFunction.go
Normal file
15
src/scanner/scanFunction.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.urbach.dev/cli/q/src/fs"
|
||||||
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// scanFunction scans a function.
|
||||||
|
func (s *scanner) scanFunction(file *fs.File, tokens token.List, i int) (int, error) {
|
||||||
|
for i < len(tokens) && tokens[i].Kind != token.BlockEnd {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
|
}
|
35
src/scanner/scanImport.go
Normal file
35
src/scanner/scanImport.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package scanner
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"git.urbach.dev/cli/q/src/errors"
|
||||||
|
"git.urbach.dev/cli/q/src/fs"
|
||||||
|
"git.urbach.dev/cli/q/src/global"
|
||||||
|
"git.urbach.dev/cli/q/src/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// scanImport scans an import.
|
||||||
|
func (s *scanner) scanImport(file *fs.File, tokens token.List, i int) (int, error) {
|
||||||
|
i++
|
||||||
|
|
||||||
|
if tokens[i].Kind != token.Identifier {
|
||||||
|
return i, errors.New(expectedPackageName, file, tokens[i].Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
packageName := tokens[i].String(file.Bytes)
|
||||||
|
fullPath := filepath.Join(global.Library, packageName)
|
||||||
|
stat, err := os.Stat(fullPath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return i, errors.New(err, file, tokens[i].Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !stat.IsDir() {
|
||||||
|
return i, errors.New(&isNotDirectory{Path: fullPath}, file, tokens[i].Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.queueDirectory(fullPath, packageName)
|
||||||
|
return i, nil
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.urbach.dev/cli/q/src/build"
|
"git.urbach.dev/cli/q/src/build"
|
||||||
|
"git.urbach.dev/cli/q/src/errors"
|
||||||
"git.urbach.dev/cli/q/src/fs"
|
"git.urbach.dev/cli/q/src/fs"
|
||||||
"git.urbach.dev/cli/q/src/token"
|
"git.urbach.dev/cli/q/src/token"
|
||||||
)
|
)
|
||||||
|
@ -141,5 +142,27 @@ func (s *scanner) scanFile(path string, pkg string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.files <- file
|
s.files <- file
|
||||||
|
|
||||||
|
for i := 0; i < len(tokens); i++ {
|
||||||
|
switch tokens[i].Kind {
|
||||||
|
case token.NewLine:
|
||||||
|
case token.Comment:
|
||||||
|
case token.Identifier:
|
||||||
|
i, err = s.scanFunction(file, tokens, i)
|
||||||
|
case token.Import:
|
||||||
|
i, err = s.scanImport(file, tokens, i)
|
||||||
|
case token.EOF:
|
||||||
|
return nil
|
||||||
|
case token.Invalid:
|
||||||
|
return errors.New(&invalidCharacter{Character: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||||
|
default:
|
||||||
|
return errors.New(&invalidTopLevel{Instruction: tokens[i].String(file.Bytes)}, file, tokens[i].Position)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue