Skip to content

Instantly share code, notes, and snippets.

@jaekwon
Last active July 6, 2020 22:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaekwon/375caac9c33b6c8f2a8e9300da91b7e9 to your computer and use it in GitHub Desktop.
Save jaekwon/375caac9c33b6c8f2a8e9300da91b7e9 to your computer and use it in GitHub Desktop.
// Challenge 1 June 29th 2020: implement a binary operation parser.
// It must be implemented in Go, and the only import allowed is "strings".
// For bonus points, implement the scanner functions.
// The solution must start with comments with the following information:
// Your name, any open-source project links (on github, gitlab, anything publicly accessible).
// We are looking for elegance of implementation.
// Test cases are not necessary, we will test code automatically, so keep the method signatures.
// Email solutions to jae+challenge@tendermint.com.
// For questions, email there or respond to @jaekwon's latest tweets.
// NOTE Sharing your solution, or hints, will disqualify you and everyone involved from future challenges.
// Tweet, if you love toxicity: https://twitter.com/jaekwon/status/1276780601761320961
package challenge1
import "strings"
var sp = " "
var prec5 = strings.Split("* / % << >> & &^", sp)
var prec4 = strings.Split("+ - | ^", sp)
var prec3 = strings.Split("== != < <= > >=", sp)
var prec2 = strings.Split("&&", sp)
var prec1 = strings.Split("||", sp)
var precs = [][]string{prec1, prec2, prec3, prec4, prec5}
// Splits a Go expression into left and right parts.
// Returns idx=-1 if not a binary operator.
// Precedence Operator
// 5 * / % << >> & &^
// 4 + - | ^
// 3 == != < <= > >=
// 2 &&
// 1 ||
//
// Examples:
// - "5 * 2": left="5 ", op="*", right=" 2", ok=true
// - " 5*2 ": left=" 5", op="*", right="2 ", ok=true
// - "1*2+ 3": left="1*2", op="+", right=" 3", ok=true
// - "1*2+(3+ 4)": left="1*2", op="+", right="(3+ 4)", ok=true
// - "'foo'+'bar'": left="'foo'", op="+", right="'bar'", ok=true
// - "'x'": ok=false
//
// Never panics.
func chopBinaryOperator(expr string) (left, op, right string, ok bool) {
// XXX Implement this.
// The methods for "scanner" are provided below and omitted with '...'.
// For bonus points, implement all the scanner methods (with method signatures as is).
}
// You can assume that the scanner functions below are implemented.
type runestate int
const (
runestateCode runestate = 0
runestateRune scanestate = 1
runestateStringQuote runestate = 2
runestateStringBacktick runestate = 3
)
type scanner struct {
str string
rnz []rune
idx int
runestate
curly int
round int
square int
}
// returns a new scanner.
func newScanner(str string) *scanner {
rnz := make([]rune, 0, len(str))
for _, r := range str {
rnz = append(rnz, r)
}
return &scanner{
str: str,
rnz: rnz,
}
}
// Peeks the next n runes and returns a string. returns a shorter string if
// there are less than n runes left.
// e.g. if the next rules are '+' followed by '=', followed by end of file,
// peek(2) returns "+=", and so would peek(3) because eof.
func (ss *scanner) peek(n int) string {
...
}
// Advance a single rune, e.g. by incrementing ss.curly if ss.rnz[ss.idx] is
// '{' before advancing. If ss.runestate is runestateRune or runestateQuote,
// advances escape sequences to completion so ss.idx may increment more than
// one. Returns true if done.
func (ss *scanner) advance() bool {
...
}
// returns true if no runes left to advance.
func (ss *scanner) done() bool {
return ss.idx == len(ss.rnz)
}
// returns true if outside the scope of any
// parentheses, brackets, strings, or rune literals.
func (ss *scanner) out() bool {
return ss.runestate == runestateCode &&
ss.curly == 0 &&
ss.round == 0 &&
ss.square == 0
}
// Advances runes, while checking that each passes `check`. if error, panics
// with info including `back` runes back.
func (ss *scanner) eatRunes(back int, eat int, check func(rune) bool) {
...
}
// increments idx until escape sequence is complete.
// returns true if done.
func (ss *scanner) advanceEscapeSequence() bool {
...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment