Cleans up readme, removes all calls to panic and replaces them with managed error messages, removes dead words from word map

master
sloum 2 months ago
parent 5b13081920
commit 26762d796b

@ -118,10 +118,11 @@ A major limitation, and thus an adjustment when coming to nimf from many other l
Variables can be named anything you like with the following exceptions:
- A variable, or a word for that matter, cannot dontain only digits (ex. `23`) as the interpreter will treat this as an integer
- A variable, or a word for that matter, cannot contain only digits (ex. `23`) as the interpreter will treat this as an integer
- A variable or word name cannot take the form of a decimal, hexidecimal, octal, or binary number. Using numbers in a var name or word is fine, so long as they do not match the established patterns for these number forms
- A variable or word name cannot contain whitespace
As a convention, not enforced at a code level, can create private words by using the following variable/word naming scheme: _module-name_.private._name_. For example: `url.private.port` would be part of the `url` module and is intended to only be used internally so is marked private, it is then given the name `port`. Using `private` in this way excludes any variables and words containing `.private.` from the word listing provided with the word `words`. In reality you can still call private words if you like, but private is one way a developer can provide intent to other developers.
As a convention, not enforced at a code level, private words can be created by using the following variable/word naming scheme: _module-name_.private._name_. For example: `url.private.port` would be part of the `url` module and is intended to only be used internally so is marked private, it is then given the name `port`. Using `private` in this way excludes any variables and words containing `.private.` from the word listing provided with the word `words`. In reality you can still call private words if you like, but private is one way a developer can provide intent to other developers.
#### General Variables

@ -56,18 +56,12 @@ func initBuiltins() {
builtins["halt"] = sysExit
builtins["words"] = words
builtins["sleep"] = sleep
builtins[":"] = func() {}
builtins[";"] = func() {}
builtins["module-end"] = func() {}
builtins["("] = func() {}
builtins[")"] = func() {}
builtins["see"] = showSubroutine
builtins["if"] = nimfIf
builtins["else"] = nimfElse
builtins["then"] = nimfThen
builtins["do"] = do
builtins["loop"] = loop
builtins["inline"] = func() {}
builtins["error"] = throwError
builtins["winsize"] = winsize
builtins["timenow"] = timenow
@ -214,7 +208,8 @@ func pick() {
return
}
if data.Pointer-count < 0 {
panic("Stack underflow")
handleError(fmt.Errorf("Stack underflow"))
return
}
data.Push(data.stack[data.Pointer-count])
@ -293,13 +288,7 @@ func sysExit() {
func throwError() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "error", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "error"))
return
}
length := memory.Get(tempString)
@ -312,7 +301,6 @@ func throwError() {
out.WriteRune(rune(num))
}
}
handleError(fmt.Errorf("%s", out.String()))
}
@ -341,8 +329,8 @@ func words() {
func showSubroutine() {
name, err := scanner.Read()
if err != nil {
// TODO make this use an actual error system
panic("show subroutine panic")
handleError(fmt.Errorf("show subroutine panic"))
return
}
nameString := name.String()
if val, ok := names[nameString]; ok {
@ -357,13 +345,8 @@ func showSubroutine() {
func do() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "do", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "do"))
return
} else {
memory.Put(actionLoopCounter, &address)
}
@ -371,13 +354,8 @@ func do() {
func loop() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "loop", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "loop"))
return
} else {
truthiness := data.Pop()
if truthiness != 0 {
@ -395,13 +373,8 @@ func loop() {
// Starts an if branch
func nimfIf() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "if", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "if"))
return
} else {
// Increment depth
memory.Set(conditionalDepthCounter, memory.Get(conditionalDepthCounter)+1)
@ -436,21 +409,11 @@ func nimfIf() {
// Starts the else in an if
func nimfElse() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "else", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "else"))
return
} else if memory.Get(conditionalDepthCounter) < 1 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found (without a preceeding %q) line %d of %s", "else", "if", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found (without a preceeding %q)", "else", "if"))
return
} else {
truthiness := address.Peep()
if truthiness == 0 {
@ -464,21 +427,11 @@ func nimfElse() {
// Ends a conditional
func nimfThen() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "then", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "then"))
return
} else if memory.Get(conditionalDepthCounter) < 1 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found (without a preceeding %q) line %d of %s", "then", "if", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found (without a preceeding %q)", "then", "if"))
return
} else {
address.Pop()
memory.Set(conditionalDepthCounter, memory.Get(conditionalDepthCounter)-1)
@ -515,13 +468,8 @@ func getEnv() {
func exitWord() {
if memory.Get(actionModeFlag) == 0 {
tok, err := scanner.PeekLast()
if err != nil {
// TODO this will need a better message that makes it clear than there was an error throwing an error
handleError(err)
} else {
handleError(fmt.Errorf("The word %q was found outside of a subroutine body on line %d of %s", "exit", tok.line, tok.file))
}
handleError(fmt.Errorf("The word %q was found outside of a subroutine body", "exit"))
return
} else {
memory.Set(exitFlag, -1)
}
@ -635,7 +583,8 @@ func bufferedInputRequest() {
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
panic(err)
handleError(err)
return
}
text = strings.TrimSuffix(text, "\n")
golangStringToNimf(text)
@ -693,9 +642,14 @@ func connClose() {
func openFile() {
mode := data.Pop()
stringAddress := data.Pop()
if limitIO {
handleError(fmt.Errorf("Nimf is running in a mode that does not allow file IO"))
return
}
fileName, err := nimfStringToGolang(stringAddress)
if err != nil {
panic("Null path (0 length) provided to file-open")
handleError(fmt.Errorf("Null path (0 length) provided to file-open"))
return
}
var modeFlag int
@ -713,7 +667,9 @@ func openFile() {
file, err = os.OpenFile(fileName, modeFlag, 0644)
if err != nil {
panic(err.Error())
data.Push(0)
handleError(err)
return
}
if mode == int('r') {
fileReader = bufio.NewReader(file)
@ -722,9 +678,14 @@ func openFile() {
func fileExists() {
stringAddress := data.Pop()
if limitIO {
handleError(fmt.Errorf("Nimf is running in a mode that does not allow file IO"))
return
}
str, err := nimfStringToGolang(stringAddress)
if err != nil {
panic("Invalid string provided to file-exists?")
handleError(fmt.Errorf("Invalid string provided to file-exists?"))
return
}
_, err = os.Stat(str)
if err != nil {
@ -737,7 +698,8 @@ func fileExists() {
func readWholeFile(fileName string) {
b, err := ioutil.ReadFile(fileName)
if err != nil {
panic(err.Error())
handleError(err)
return
}
text := string(b)
length := len(text)
@ -752,7 +714,8 @@ func readLine() {
if err == io.EOF {
data.Push(0)
} else if err != nil {
panic(err.Error())
handleError(err)
return
} else {
golangStringToNimf(line)
data.Push(-1)
@ -763,11 +726,13 @@ func writeToFile() {
stringAddress := data.Pop()
str, err := nimfStringToGolang(stringAddress)
if err != nil {
panic("Invalid string provided to file-write")
handleError(fmt.Errorf("Invalid string provided to file-write"))
return
}
_, err = fmt.Fprint(file, str)
if err != nil {
panic(err.Error())
handleError(err)
return
}
}
@ -777,16 +742,22 @@ func closeFile() {
}
err := file.Close()
if err != nil {
panic(err.Error())
handleError(err)
return
}
file = nil
}
func addSubprocess() {
address := data.Pop()
if limitIO {
handleError(fmt.Errorf("Nimf is running in a mode that does not allow file IO"))
return
}
procString, err := nimfStringToGolang(address)
if err != nil {
panic("Invalid process string provided to subproc.create")
handleError(fmt.Errorf("Invalid process string provided to subproc.create"))
return
}
procFields := strings.Fields(procString)
processWrite = false
@ -799,23 +770,31 @@ func addSubprocess() {
func pipeToSubprocess() {
address := data.Pop()
if limitIO {
handleError(fmt.Errorf("Nimf is running in a mode that does not allow file IO"))
return
}
dataString, err := nimfStringToGolang(address)
if err != nil {
panic("Invalid input string provided to subproc.send")
handleError(fmt.Errorf("Invalid input string provided to subproc.send"))
return
}
if process == nil {
panic("There is not a current process, create one with subproc.create")
handleError(fmt.Errorf("There is not a current process, create one with subproc.create"))
return
}
stdin, err := process.StdinPipe()
if err != nil {
panic(err.Error())
handleError(err)
return
}
go func() {
defer stdin.Close()
_, err := fmt.Fprint(stdin, dataString)
if err != nil {
panic(err.Error())
handleError(err)
return
}
processWrite = true
}()
@ -823,12 +802,17 @@ func pipeToSubprocess() {
func runSubprocess() {
mode := data.Pop()
if limitIO {
handleError(fmt.Errorf("Nimf is running in a mode that does not allow file IO"))
return
}
switch mode {
case int('q'):
// Quick/Non-Interactive Mode
out, err := process.CombinedOutput()
if err != nil {
panic(err.Error())
handleError(err)
return
}
output := string(out)
if len(output) > 0 {
@ -844,25 +828,33 @@ func runSubprocess() {
process.Stdout = os.Stdout
err := process.Run()
if err != nil {
panic(err.Error())
handleError(err)
return
}
case int('b'):
// Background Mode
err := process.Start()
if err != nil {
panic(err.Error())
handleError(err)
return
}
default:
panic("Invalid mode sent to subproc.exec")
handleError(fmt.Errorf("Invalid mode sent to subproc.exec"))
return
}
process = nil
}
func procWorkingDir() {
pathAddress := data.Pop()
if limitIO {
handleError(fmt.Errorf("Nimf is running in a mode that does not allow file IO"))
return
}
path, err := nimfStringToGolang(pathAddress)
if err != nil {
panic("Invalid path string provided to subproc.cd")
handleError(fmt.Errorf("Invalid path string provided to subproc.cd"))
return
}
path = expandedAbsFilepath(path)
process.Dir = path

@ -314,8 +314,43 @@ func getReplInput() []token {
return parse(text, true)
}
func handleParseError(e error, l int, f, tok string) {
errTemplate := "\033[91;1mError: \033[0m\033[1m%s\033[0m\n\nline : %d\nfile : %s\ntoken: %s\n\n"
fmt.Fprintf(os.Stderr, errTemplate, e.Error(), l, f, tok)
if interactive {
parseError = true
reset = true
data.Pointer, address.Pointer = -1, -1
memory.Set(3, 0) // string mode is off
memory.Set(4, 0) // string mode is off
memory.Set(8, 0) // branch depth is 0
memory.Set(9, 0) // loop depth is 0
memory.Set(11, 0) // variable setting is off
} else {
os.Exit(1)
}
}
func handleError(e error) {
fmt.Fprintf(os.Stderr, "\033[91;1mError:\n\033[0m\033[1m%s\033[0m\n", e.Error())
line := -1
file := "error tracing file"
token := "error tracing token"
t, err := scanner.PeekLast()
if err != nil {
t, err = scanner.Read()
if err == nil {
scanner.Unread()
line = t.line
file = t.file
token = t.String()
}
} else {
line = t.line
file = t.file
token = t.String()
}
errTemplate := "\033[91;1mError: \033[0m\033[1m%s\033[0m\n\nline : %d\nfile : %s\ntoken: %s\n\n"
fmt.Fprintf(os.Stderr, errTemplate, e.Error(), line, file, token)
if interactive {
reset = true
data.Pointer, address.Pointer = -1, -1

@ -11,7 +11,7 @@ import (
const (
name string = "nimf"
version string = "1.0"
version string = "1.02"
)
var memoryAmt int = 250000
@ -35,6 +35,7 @@ var scanner *tokenReader
// Run mode
var interactive bool = true
var reset bool = false
var limitIO bool = false // Used for code playgrounds or other situations where IO access should be limited
func action(sr []token) {
locals := make(map[string]int)
@ -52,7 +53,7 @@ func action(sr []token) {
if memory.ValueEquals(localAssignmentFlag, -1) {
memory.Set(localAssignmentFlag, 0)
if sr[i].tokType != wordType {
handleError(fmt.Errorf("Invalid var name: %q at line %d of %s", sr[i].String(), sr[i].line, sr[i].file))
handleError(fmt.Errorf("Invalid var name: %q", sr[i].String()))
return
}
locals[sr[i].String()] = memory.pointer + memory.lpointer
@ -102,7 +103,7 @@ func execute(field token) {
// If we are setting a var value
// If the word already exists throw an error
if _, ok := names[field.String()]; ok {
handleError(fmt.Errorf("Tried to create a var, %q, at line %d in %s that already exists", field.String(), field.line, field.file))
handleError(fmt.Errorf("Tried to create a var, %q, that already exists", field.String()))
return
}
names[field.String()] = []token{
@ -125,7 +126,7 @@ func execute(field token) {
// Execute the builtin
val()
} else {
handleError(fmt.Errorf("Unknown word: %s. Found on line %d in %s", field.String(), field.line, field.file))
handleError(fmt.Errorf("Unknown word: %s", field.String()))
}
}
@ -138,6 +139,7 @@ func main() {
memoryAmt := flag.Int("memory", 250000, "Total memory blocks (minimum = 35000)")
runCommand := flag.String("run", "", "A quoted string of commands to run and then exit")
printVersion := flag.Bool("v", false, "Print the version string")
limitIOFlag := flag.Bool("limit-io", false, "Disable file based IO and subprocess creation")
flag.Parse()
if *printVersion {
@ -145,6 +147,8 @@ func main() {
os.Exit(0)
}
limitIO = *limitIOFlag
if *memoryAmt < 35000 {
fmt.Fprintf(os.Stderr, "%d is not enough memory. Please supply at least 35000 or use the default (250000)", *memoryAmt)
os.Exit(1)

@ -71,20 +71,23 @@ func (m *systemMemory) Allocate(cells int) {
m.pointer += cells
if m.pointer >= memoryAmt {
m.pointer = memoryAmt - 1
panic("Out of memory")
handleError(fmt.Errorf("Out of memory"))
return
}
}
func (m *systemMemory) Set(address, value int) {
if address < 0 || address > memoryAmt-1 {
panic(fmt.Sprintf("Memory address %d is out of range", address))
handleError(fmt.Errorf("Memory address %d is out of range", address))
return
}
m.memory[address] = value
}
func (m *systemMemory) SetString(address int) {
if address < 50 || address > memoryAmt-1 {
panic(fmt.Sprintf("Cannot set string: memory address %d is out of range", address))
handleError(fmt.Errorf("Cannot set string: memory address %d is out of range", address))
return
}
length := memory.Get(tempString)
if length <= 0 {
@ -92,7 +95,8 @@ func (m *systemMemory) SetString(address int) {
return
}
if address+length > memoryAmt-1 {
panic(fmt.Sprintf("There is not enough memory available to store %d characters at %X", length, address))
handleError(fmt.Errorf("There is not enough memory available to store %d characters at %X", length, address))
return
}
for i := 0; i < length+1; i++ {
memory.Set(address, memory.Get(tempString+i))
@ -103,14 +107,17 @@ func (m *systemMemory) SetString(address int) {
// Takes start and end _addresses_, not offsets
func (m *systemMemory) GetString(start, end int) {
if start < 50 || start > memoryAmt-1 || end < start || end > memoryAmt-1 {
panic(fmt.Sprintf("Cannot get string: memory address %d - %d is out of range", start, end))
handleError(fmt.Errorf("Cannot get string: memory address %d - %d is out of range", start, end))
return
}
length := end - start + 1
if length <= 0 {
panic(fmt.Sprintf("String length is less than zero"))
handleError(fmt.Errorf("String length is less than zero"))
return
}
if 50+length > 29999 {
panic(fmt.Sprintf("There is not enough memory available to store %d characters in the temporary string buffer", length))
handleError(fmt.Errorf("There is not enough memory available to store %d characters in the temporary string buffer", length))
return
}
memory.Set(tempString, length) // Set the length
memory.tspointer = 51 // Start at the first char
@ -124,21 +131,24 @@ func (m *systemMemory) GetString(start, end int) {
func (m *systemMemory) Get(from int) int {
if from < 0 || from > memoryAmt-1 {
panic(fmt.Sprintf("Memory address %d is out of range", from))
handleError(fmt.Errorf("Memory address %d is out of range", from))
return 0
}
return m.memory[from]
}
func (m *systemMemory) Put(from int, to *stack) {
if from < 0 || from > memoryAmt-1 {
panic(fmt.Sprintf("Memory address %d is out of range", from))
handleError(fmt.Errorf("Memory address %d is out of range", from))
return
}
to.Push(m.memory[from])
}
func (m *systemMemory) ValueEquals(from, value int) bool {
if from < 0 || from > memoryAmt-1 {
panic(fmt.Sprintf("Memory address %d is out of range", from))
handleError(fmt.Errorf("Memory address %d is out of range", from))
return false
}
return m.memory[from] == value
}

@ -16,6 +16,8 @@ const (
wordType
)
var parseError bool = false
type tokenReader struct {
slice []token
pc int
@ -77,6 +79,10 @@ func parse(f string, repl bool) []token {
out := make([]token, 0, len(stream))
reader := NewTokenReader(stream)
for reader.Len() > 0 {
if parseError {
parseError = false
return []token{}
}
tok, err := reader.Read()
if err != nil {
break
@ -144,10 +150,12 @@ func eatWordDefinition(r *tokenReader, file string, line int) {
// Vet the name
nameTok, err := r.Read()
if err != nil {
panic(fmt.Sprintf("Error eating word definition on line %d in %s", line, file))
handleParseError(fmt.Errorf("Error eating word definition: end of token stream"), line, file, "")
return
}
if nameTok.tokType != wordType || nameTok.String() == ";" {
panic(fmt.Sprintf("Invalid word name while eating word definition on line %d in %s", line, file))
handleParseError(fmt.Errorf("Invalid word name while eating word definition"), line, file, nameTok.String())
return
}
name := nameTok.String()
def := make([]token, 0, 10)
@ -156,7 +164,8 @@ ParseLoop:
for {
t, err := r.Read()
if err != nil {
panic(fmt.Sprintf("End of input file reached before close of word definition %q in file %s", name, nameTok.file))
handleParseError(fmt.Errorf("End of input file reached before close of word definition %q", name), nameTok.line, nameTok.file, "")
return
}
if t.tokType == stringType || t.tokType == intType {
def = append(def, t)
@ -165,20 +174,23 @@ ParseLoop:
case ";":
break ParseLoop
case "inline":
panic(fmt.Sprintf("Error while parsing word definition %q. Found an %q directive on line %d of %s. Cannot inline from within a word", name, "inline", t.line, t.file))
handleParseError(fmt.Errorf("Error while parsing word definition %q. Cannot inline from within a word definition", name), t.line, t.file, "inline")
return
case "if":
ifTok++
def = append(def, t)
case "else":
elseTok++
if elseTok > ifTok {
panic(fmt.Sprintf("Error while parsing word definition %q on line %d of %s. Cannot use 'else' before a similarly nested 'if'", name, t.line, t.file))
handleParseError(fmt.Errorf("Error while parsing word definition %q. Cannot use 'else' before a similarly nested 'if'", name), t.line, t.file, "else")
return
}
def = append(def, t)
case "then":
thenTok++
if thenTok > ifTok {
panic(fmt.Sprintf("Error while parsing word definition %q on line %d of %s. Cannot use 'then' before a similarly nested 'if'", name, t.line, t.file))
handleParseError(fmt.Errorf("Error while parsing word definition %q. Cannot use 'then' before a similarly nested 'if'", name), t.line, t.file, "then")
return
}
def = append(def, t)
case "do":
@ -187,18 +199,21 @@ ParseLoop:
case "loop":
loopTok++
if loopTok > doTok {
panic(fmt.Sprintf("Error while parsing word definition %q on line %d of %s. Cannot use 'loop' before a similarly nested 'do'", name, t.line, t.file))
handleParseError(fmt.Errorf("Error while parsing word definition %q. Cannot use 'loop' before a similarly nested 'do'", name), t.line, t.file, "loop")
return
}
def = append(def, t)
case ":":
panic(fmt.Sprintf("Error while parsing word definition %q on line %d of %s. Cannot use ':' to create a word within a word definition", name, t.line, t.file))
handleParseError(fmt.Errorf("Error while parsing word definition %q. Cannot use ':' to create a word within a word definition", name), t.line, t.file, ":")
return
default:
def = append(def, t)
}
}
}
if doTok != loopTok || ifTok != thenTok {
panic(fmt.Sprintf("The word definition for %q found on line %d of %s contains an unbalanced conrol structures", name, nameTok.line, nameTok.file))
handleParseError(fmt.Errorf("The word definition for %q contains an unbalanced conrol structure", name), nameTok.line, nameTok.file, "")
return
}
names[name] = def
@ -226,6 +241,9 @@ func lex(f string, repl bool) []token {
TokenizationLoop:
for reader.Len() > 0 {
if parseError {
return []token{}
}
c, _, err := reader.ReadRune()
if err != nil {
break TokenizationLoop
@ -259,7 +277,8 @@ func eatChar(r *strings.Reader, currentLine *int, fn string) token {
}
charRunes := []rune(wn)
if len(charRunes) != 2 {
panic(fmt.Sprintf("Lexing error while lexing char. Received invalid char construct: %s\n\tLine: %d\n\tFile: %s", wn, *currentLine, fn))
handleParseError(fmt.Errorf("Lexing error while lexing char. Received invalid char construct: %s", wn), *currentLine, fn, wn)
return token{}
}
return token{
t: int(charRunes[1]),
@ -274,7 +293,8 @@ func eatWordNumber(r *strings.Reader, currentLine *int, fn string) token {
for r.Len() > 0 {
c, _, err := r.ReadRune()
if err != nil {
panic(fmt.Sprintf("Lexing error while lexing string on line %d of %s", *currentLine, fn))
handleParseError(fmt.Errorf("Lexing error, EOF"), *currentLine, fn, "")
return token{}
}
if unicode.IsSpace(c) {
r.UnreadRune()
@ -335,7 +355,8 @@ func eatComment(r *strings.Reader, currentLine *int, fn string) {
for r.Len() > 0 {
c, _, err := r.ReadRune()
if err != nil {
panic(fmt.Sprintf("Lexing error while eating comment on line %d of %s", *currentLine, fn))
handleParseError(fmt.Errorf("Lexing error EOF"), *currentLine, fn, "")
return
}
if c == '\n' {
*currentLine++
@ -353,7 +374,8 @@ func eatString(r *strings.Reader, currentLine *int, fn string) token {
for r.Len() > 0 {
c, _, err := r.ReadRune()
if err != nil {
panic(fmt.Sprintf("Lexing error while lexing string on line %d of %s", *currentLine, fn))
handleParseError(fmt.Errorf("Lexing error EOF"), *currentLine, fn, "")
return token{}
}
if c == '"' && (escapeCount == 0 || escapeCount%2 == 0) {
break
@ -384,7 +406,8 @@ func eatWhitespace(r *strings.Reader, currentLine *int, fn string) {
for r.Len() > 0 {
c, _, err := r.ReadRune()
if err != nil {
panic(fmt.Sprintf("Lexing error while eating whitespace on line %d of %s", *currentLine, fn))
handleParseError(fmt.Errorf("Lexing error EOF"), *currentLine, fn, "")
return
}
if c == '\n' {
*currentLine++
@ -415,7 +438,8 @@ func eatShebang(r *strings.Reader, currentLine *int, fn string) {
for r.Len() > 0 {
c, _, err := r.ReadRune()
if err != nil {
panic(fmt.Sprintf("Lexing error while eating shebang on line %d of %s", *currentLine, fn))
handleParseError(fmt.Errorf("Lexing error EOF"), *currentLine, fn, "")
return
}
if c == '\n' {
*currentLine++

Loading…
Cancel
Save