func lexHexConstant(l *Lexer) (Token, interface{}) { startPos := l.pos endPos := l.pos for { //Find the end of the constant if l.hasNextFunc(char.IsHexDigit) { endPos++ } else { //Check if the number is invalid. //We already know the next rune is not a hex digit if char.IsInVarName(l.peek()) { return ArithError, LexError{ X: l.input[startPos-2 : endPos+1], Err: ErrHexConstant, } } break } } parsedVal, err := strconv.ParseInt(l.input[startPos:endPos], 16, 64) if err != nil { panic("Not Reached: Broken Hex Constant") } return ArithNumber, parsedVal }
func IsAssignment(s string) bool { rs := []rune(s) if !char.IsFirstInVarName(rs[0]) { return false } for _, c := range rs[1:] { if !char.IsInVarName(c) { return c == '=' } } return false }
func IsGoodName(s string) bool { rs := []rune(s) if !char.IsFirstInVarName(rs[0]) { return false } for _, c := range rs[1:] { if !char.IsInVarName(c) { return false } } return true }
func (l *Lexer) VariableSimple() { // When we enter this state we know we have at least one readable // char for the varname. That means that any character not valid // just terminates the parsing and we dont have to // worry about the case of an empty varname l.buffer.WriteRune(SentinalSubstitution) sv := SubVariable{SubType: VarSubNormal} varbuf := bytes.Buffer{} c := l.nextChar() switch { case char.IsSpecial(c): varbuf.WriteRune(c) case char.IsDigit(c): // Positional argv for { varbuf.WriteRune(c) c = l.nextChar() if !char.IsDigit(c) { l.backup() break } } case char.IsFirstInVarName(c): for { varbuf.WriteRune(c) c = l.nextChar() if !char.IsInVarName(c) { l.backup() break } } default: l.backup() } sv.VarName = varbuf.String() l.subs = append(l.subs, sv) return }
func lexOctalConstant(l *Lexer) (Token, interface{}) { startPos := l.pos - l.lastRuneWidth endPos := l.pos for { if l.hasNextFunc(char.IsOctalDigit) { endPos++ } else { if char.IsInVarName(l.peek()) { return ArithError, LexError{ X: l.input[startPos-1 : endPos+1], Err: ErrOctalConstant, } } break } } parsedVal, err := strconv.ParseInt(l.input[startPos:endPos], 8, 64) if err != nil { panic("Not Reached: Broken Octal Constant") } return ArithNumber, parsedVal }
func (l *Lexer) VariableComplex() { // Upon entering we have read the opening '{' l.buffer.WriteRune(SentinalSubstitution) sv := SubVariable{} varbuf := bytes.Buffer{} defer func() { // We defer this as there are multiple return points sv.VarName = varbuf.String() l.subs = append(l.subs, sv) }() if l.hasNext('#') { // The NParam Special Var if l.hasNext('}') { varbuf.WriteRune('#') return } // Length variable operator sv.SubType = VarSubLength } c := l.nextChar() switch { case char.IsSpecial(c): varbuf.WriteRune(c) case char.IsDigit(c): for { varbuf.WriteRune(c) c = l.nextChar() if !char.IsDigit(c) { l.backup() break } } case char.IsFirstInVarName(c): for { varbuf.WriteRune(c) c = l.nextChar() if !char.IsInVarName(c) { l.backup() break } } case c == EOFRune: l.backup() return } // Either a Enclosed variable '${foo}' or a length operation '${#foo}' if l.hasNext('}') { return } // Length operator should have returned since only ${#varname} is valid if sv.SubType == VarSubLength { l.log.Error("Line %d: Bad substitution (%s)", l.lineNo, l.input[l.lastPosition:l.position]) os.Exit(1) } if l.hasNext(':') { sv.CheckNull = true } switch l.nextChar() { case '-': sv.SubType = VarSubMinus case '+': sv.SubType = VarSubPlus case '?': sv.SubType = VarSubQuestion case '=': sv.SubType = VarSubAssign case '#': if l.hasNext('#') { sv.SubType = VarSubTrimLeftMax } else { sv.SubType = VarSubTrimLeft } case '%': if l.hasNext('%') { sv.SubType = VarSubTrimRightMax } else { sv.SubType = VarSubTrimRight } default: l.log.Error("Line %d: Bad substitution (%s)", l.lineNo, l.input[l.lastPosition:l.position]) os.Exit(1) } // Read until '}' // In the future to support Nested vars etc create new sublexer from // l.input[l.pos:] and take the first lexitem as the sub val then adjust // this lexer's position and trash sublexer c = l.nextChar() subValBuf := bytes.Buffer{} for { if c == '}' { break } subValBuf.WriteRune(c) c = l.nextChar() } sv.SubVal = subValBuf.String() }