Last active
July 6, 2020 22:08
-
-
Save jaekwon/375caac9c33b6c8f2a8e9300da91b7e9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 [email protected]. | |
// 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