diff options
| author | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-20 11:42:47 +0100 | 
|---|---|---|
| committer | Charlie Stanton <charlie@shtanton.xyz> | 2023-04-20 11:42:47 +0100 | 
| commit | c1c33227ab72de1e5f21a08ee74c3df667148343 (patch) | |
| tree | 6eb70d5bfa54a69129cdce14ea1b8902f23364c6 | |
| parent | a0a416e7762fcdcc066617da8083b0372b87155c (diff) | |
| download | stred-go-c1c33227ab72de1e5f21a08ee74c3df667148343.tar | |
Adds non-string literal syntax to subex
| -rw-r--r-- | subex/parse.go | 83 | ||||
| -rw-r--r-- | subex/subexast.go | 6 | 
2 files changed, 89 insertions, 0 deletions
| diff --git a/subex/parse.go b/subex/parse.go index e6efc2e..f95fd9f 100644 --- a/subex/parse.go +++ b/subex/parse.go @@ -2,6 +2,8 @@ package subex  import (  	"main/walk" +	"strconv" +	"strings"  )  type RuneReader interface { @@ -45,6 +47,68 @@ func parseTerminatorAtomLiteral(termType rune, l RuneReader) walk.Atom {  	}  } +func isNumericRune(r rune) bool { +	return '0' <= r && r <= '9' || r == '.' +} + +// Having just parsed a `, read until the next ` and parse the contents into a list of non-string atoms +func parseNonStringLiteral(l RuneReader) (literals []walk.Atom) { +	for { +		r := l.Next() +		if isNumericRune(r) { +			var builder strings.Builder +			builder.WriteRune(r) +			for { +				r := l.Next() +				if !isNumericRune(r) { +					l.Rewind() +					break +				} +				builder.WriteRune(r) +			} +			numberString := builder.String() +			number, err := strconv.ParseFloat(numberString, 64) +			if err != nil { +				panic("Invalid number literal") +			} +			literals = append(literals, walk.ValueNumber(number)) +			continue +		} +		switch r { +			case '`': +				return literals +			case ' ', '\t': +				continue +			case 'n': +				if accept(l, "u") && accept(l, "l") && accept(l, "l") { +					literals = append(literals, walk.ValueNull{}) +				} else { +					panic("Invalid literal") +				} +			case 't': +				if accept(l, "r") && accept(l, "u") && accept(l, "e") { +					literals = append(literals, walk.ValueBool(true)) +				} else { +					panic("Invalid literal") +				} +			case 'f': +				if accept(l, "a") && accept(l, "l") && accept(l, "s") && accept(l, "e") { +					literals = append(literals, walk.ValueBool(false)) +				} else { +					panic("Invalid literal") +				} +			case '{': +				literals = append(literals, walk.MapBegin) +			case '}': +				literals = append(literals, walk.MapEnd) +			case '[': +				literals = append(literals, walk.ArrayBegin) +			case ']': +				literals = append(literals, walk.ArrayEnd) +		} +	} +} +  func charIsDigit(c rune) bool {  	return '0' <= c && c <= '9'  } @@ -124,6 +188,11 @@ func parseReplacement(l RuneReader) (output []OutputContent) {  				output = append(output, OutputLoad{slot: slot})  			case '@', '~', '#':  				output = append(output, OutputAtomLiteral{atom: parseTerminatorAtomLiteral(r, l)}) +			case '`': +				literals := parseNonStringLiteral(l) +				for _, literal := range literals { +					output = append(output, OutputAtomLiteral {literal}) +				}  			default:  				output = append(output, OutputAtomLiteral{atom: walk.StringAtom(r)})  		} @@ -145,6 +214,10 @@ func parseRangeSubex(l RuneReader) map[walk.Atom]walk.Atom {  		} else if fromsStart == '=' {  			hasTo = true  			break +		} else if fromsStart == '`' { +			literals := parseNonStringLiteral(l) +			froms = append(froms, literals...) +			continue  		} else {  			atom := parseTerminatorAtomLiteral(fromsStart, l)  			if atom != nil { @@ -175,6 +248,10 @@ func parseRangeSubex(l RuneReader) map[walk.Atom]walk.Atom {  			tosStart := l.Next()  			if tosStart == ']' {  				break +			} else if tosStart == '`' { +				literals := parseNonStringLiteral(l) +				tos = append(tos, literals...) +				continue  			} else {  				atom := parseTerminatorAtomLiteral(tosStart, l)  				if atom != nil { @@ -232,6 +309,12 @@ func parseSubex(l RuneReader, minPower int) SubexAST {  			lhs = SubexASTCopyAny{}  		case '@', '#', '~':  			lhs = SubexASTCopyAtom{atom: parseTerminatorAtomLiteral(r, l)} +		case '`': +			literals := parseNonStringLiteral(l) +			lhs = SubexASTEmpty{} +			for _, literal := range literals { +				lhs = SubexASTConcat {lhs, SubexASTCopyAtom {literal}} +			}  		default:  			lhs = SubexASTCopyAtom{atom: walk.StringAtom(r)}  	} diff --git a/subex/subexast.go b/subex/subexast.go index fb16658..bc80835 100644 --- a/subex/subexast.go +++ b/subex/subexast.go @@ -253,3 +253,9 @@ func (ast SubexASTNot) compileWith(next SubexState) SubexState {  		}),  	}  } + +// Does nothing +type SubexASTEmpty struct {} +func (ast SubexASTEmpty) compileWith(next SubexState) SubexState { +	return next +} | 
