Adds receivers to filter and point structs
This commit is contained in:
parent
5a85f9cc8f
commit
e2b5936197
|
@ -12,3 +12,5 @@
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
|
||||||
|
# Binary from `go build`
|
||||||
|
filtress
|
||||||
|
|
|
@ -77,13 +77,6 @@ MOD [op]int
|
||||||
|
|
||||||
. . .
|
. . .
|
||||||
|
|
||||||
Set fade time:
|
|
||||||
# If set below zero, becomes zero
|
|
||||||
|
|
||||||
FAD [op]int
|
|
||||||
|
|
||||||
. . .
|
|
||||||
|
|
||||||
Doing loops:
|
Doing loops:
|
||||||
# The int after BEG represents the number of times to loop
|
# The int after BEG represents the number of times to loop
|
||||||
# At present, loops may not be nested
|
# At present, loops may not be nested
|
||||||
|
|
69
main.go
69
main.go
|
@ -1,5 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"tildegit.org/sloum/filtress/parser"
|
||||||
|
)
|
||||||
|
|
||||||
type point struct {
|
type point struct {
|
||||||
x int
|
x int
|
||||||
y int
|
y int
|
||||||
|
@ -7,21 +16,61 @@ type point struct {
|
||||||
maxY int
|
maxY int
|
||||||
}
|
}
|
||||||
|
|
||||||
type color int
|
type filter struct {
|
||||||
type mode int
|
max int
|
||||||
|
min int
|
||||||
|
val int
|
||||||
|
}
|
||||||
|
|
||||||
type filterState struct {
|
type filterState struct {
|
||||||
red color
|
red filter
|
||||||
green color
|
green filter
|
||||||
blue color
|
blue filter
|
||||||
alpha color
|
alpha filter
|
||||||
location point
|
location point
|
||||||
mod mode
|
mode filter
|
||||||
register int
|
}
|
||||||
fade uint
|
|
||||||
loop uint
|
var variables = map[string]int{}
|
||||||
|
|
||||||
|
func openFileFromPath(path string) *os.File {
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// Handle checking filter file argument
|
||||||
|
flag.Parse()
|
||||||
|
posArgs := flag.Args()
|
||||||
|
if len(posArgs) > 1 || len(posArgs) < 1 {
|
||||||
|
panic(fmt.Sprintf("Input error: Too many positional arguments. Expected one, received %d", len(flag.Args())))
|
||||||
|
}
|
||||||
|
fpath := posArgs[0]
|
||||||
|
fext := strings.ToUpper(filepath.Ext(fpath))
|
||||||
|
_, fname := filepath.Split(fpath)
|
||||||
|
|
||||||
|
if fext != ".FRS" {
|
||||||
|
panic(fmt.Sprintf("Input error: Incorrect filetype. Expected .FRS, received \".%s\"", fext))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open file and parse
|
||||||
|
fmt.Println("Filtress v0.2.0")
|
||||||
|
filterFile := openFileFromPath(fpath)
|
||||||
|
parser := parser.NewParser(filterFile)
|
||||||
|
fmt.Printf("Parsing file: %s ...\n", fname)
|
||||||
|
tree := parser.Parse()
|
||||||
|
if len(tree.Loops) > 0 {
|
||||||
|
fmt.Printf("File has %d procedures\n", len(tree.Loops))
|
||||||
|
fmt.Println("File is valid")
|
||||||
|
} else {
|
||||||
|
fmt.Println("Invalid input file")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(tree)
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package parse
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -48,11 +48,12 @@ func (s *scanner) unread() {
|
||||||
|
|
||||||
|
|
||||||
func (s *scanner) scan() Token {
|
func (s *scanner) scan() Token {
|
||||||
|
for {
|
||||||
char := s.read()
|
char := s.read()
|
||||||
|
|
||||||
if isWhitespace(char) {
|
if isWhitespace(char) {
|
||||||
s.unread()
|
s.unread()
|
||||||
return s.scanWhitespace()
|
s.scanWhitespace()
|
||||||
} else if isLetter(char) {
|
} else if isLetter(char) {
|
||||||
s.unread()
|
s.unread()
|
||||||
return s.scanText()
|
return s.scanText()
|
||||||
|
@ -61,19 +62,20 @@ func (s *scanner) scan() Token {
|
||||||
return s.scanNumber()
|
return s.scanNumber()
|
||||||
} else if char == '#' {
|
} else if char == '#' {
|
||||||
s.unread()
|
s.unread()
|
||||||
return s.scanComment()
|
s.scanComment()
|
||||||
} else if isOpperator(char) {
|
} else if isOpperator(char) {
|
||||||
return Token{Opperator, string(char)}
|
return Token{Opperator, string(char)}
|
||||||
} else if char == '\n' {
|
} else if char == '\n' {
|
||||||
return Token{Newline,""}
|
return Token{Newline,"New Line"}
|
||||||
} else if char == ':' {
|
} else if char == ':' {
|
||||||
return Token{Separator,""}
|
return Token{Separator,":"}
|
||||||
} else if char == eof {
|
} else if char == eof {
|
||||||
return Token{End, ""}
|
return Token{End, "eof"}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
return Token{Illegal, string(char)}
|
return Token{Illegal, string(char)}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *scanner) scanWhitespace() Token {
|
func (s *scanner) scanWhitespace() Token {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package parse
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
@ -45,11 +45,6 @@ func (p *Parser) scan() (current Token) {
|
||||||
return p.buffer.token
|
return p.buffer.token
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
|
||||||
if current = p.s.scan(); current.kind != Whitespace && current.kind != Comment {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
current = p.s.scan()
|
current = p.s.scan()
|
||||||
p.buffer.token = current
|
p.buffer.token = current
|
||||||
return
|
return
|
||||||
|
@ -70,8 +65,13 @@ func (p *Parser) parseExpressions(equals bool) []Expression {
|
||||||
if t.kind == Opperator {
|
if t.kind == Opperator {
|
||||||
ex.Opperator = rune(t.val[0])
|
ex.Opperator = rune(t.val[0])
|
||||||
t = p.scan()
|
t = p.scan()
|
||||||
} else {
|
} else if t.kind == Number || t.kind == Text {
|
||||||
ex.Opperator = '='
|
ex.Opperator = '='
|
||||||
|
} else if t.kind == Newline {
|
||||||
|
p.unscan()
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("Parse error: Invalid token %q on \033[1mline %d\033[0m", t.val, p.row))
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.kind == Number {
|
if t.kind == Number {
|
||||||
|
@ -86,6 +86,7 @@ func (p *Parser) parseExpressions(equals bool) []Expression {
|
||||||
|
|
||||||
exprs = append(exprs, ex)
|
exprs = append(exprs, ex)
|
||||||
|
|
||||||
|
t = p.scan()
|
||||||
if t.kind == Separator {
|
if t.kind == Separator {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -133,17 +134,12 @@ func (p *Parser) parseLoop() Loop {
|
||||||
t := p.scan()
|
t := p.scan()
|
||||||
l := Loop{}
|
l := Loop{}
|
||||||
|
|
||||||
if strings.ToUpper(t.val) == "LOOP" {
|
|
||||||
t = p.scan()
|
|
||||||
if t.kind == Number {
|
if t.kind == Number {
|
||||||
l.Counter, _ = strconv.Atoi(t.val)
|
l.Counter, _ = strconv.Atoi(t.val)
|
||||||
} else {
|
} else {
|
||||||
panic(fmt.Sprintf("Parse error: Loop declared, but not followed by a number on \033[1mline %d\033[0m", p.row))
|
panic(fmt.Sprintf("Parse error: Loop declared, but not followed by a number on \033[1mline %d\033[0m", p.row))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
p.unscan()
|
|
||||||
l.Counter = 1
|
|
||||||
}
|
|
||||||
l.Procedures = make([]Procedure,0, 5)
|
l.Procedures = make([]Procedure,0, 5)
|
||||||
|
|
||||||
L:
|
L:
|
||||||
|
@ -163,6 +159,9 @@ func (p *Parser) parseLoop() Loop {
|
||||||
case Number:
|
case Number:
|
||||||
panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row))
|
panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row))
|
||||||
case Text:
|
case Text:
|
||||||
|
if strings.ToUpper(t.val) == "END" {
|
||||||
|
break L
|
||||||
|
}
|
||||||
p.unscan()
|
p.unscan()
|
||||||
procedure := p.parseProcedure()
|
procedure := p.parseProcedure()
|
||||||
l.Procedures = append(l.Procedures, procedure)
|
l.Procedures = append(l.Procedures, procedure)
|
||||||
|
@ -193,8 +192,15 @@ func (p *Parser) Parse() AST {
|
||||||
case Number:
|
case Number:
|
||||||
panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row))
|
panic(fmt.Sprintf("Parse error: Number %q outside of procedure call on \033[1mline %d\033[0m", t.val, p.row))
|
||||||
case Text:
|
case Text:
|
||||||
|
var loop Loop
|
||||||
|
if strings.ToUpper(t.val) == "BEG" {
|
||||||
|
loop = p.parseLoop()
|
||||||
|
} else {
|
||||||
p.unscan()
|
p.unscan()
|
||||||
loop := p.parseLoop()
|
loop = Loop{1, make([]Procedure, 0, 1)}
|
||||||
|
procedure := p.parseProcedure()
|
||||||
|
loop.Procedures = append(loop.Procedures, procedure)
|
||||||
|
}
|
||||||
tree.Loops = append(tree.Loops, loop)
|
tree.Loops = append(tree.Loops, loop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,8 +211,7 @@ func (p *Parser) Parse() AST {
|
||||||
func isValidProcedure(p string) bool {
|
func isValidProcedure(p string) bool {
|
||||||
switch p {
|
switch p {
|
||||||
case "REG", "LOC", "BEG", "END", "RED",
|
case "REG", "LOC", "BEG", "END", "RED",
|
||||||
"GRN", "BLU", "APH", "COL", "APY", "MOD",
|
"GRN", "BLU", "APH", "COL", "APY", "MOD":
|
||||||
"FAD":
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -224,3 +229,5 @@ func isVariable(v string) bool {
|
||||||
func NewParser(r io.Reader) *Parser {
|
func NewParser(r io.Reader) *Parser {
|
||||||
return &Parser{s: NewScanner(r)}
|
return &Parser{s: NewScanner(r)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"tildegit.org/sloum/filtress/parser"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (f *filter) update(change parser.Expression, vars map[string]int) {
|
||||||
|
opand := change.Opperand
|
||||||
|
if change.Variable != "" {
|
||||||
|
if val, ok := vars[change.Variable]; ok {
|
||||||
|
opand = val
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch change.Opperator {
|
||||||
|
case '+':
|
||||||
|
f.val += opand
|
||||||
|
case '-':
|
||||||
|
f.val -= opand
|
||||||
|
case '*':
|
||||||
|
f.val *= opand
|
||||||
|
case '/':
|
||||||
|
if opand == 0 {
|
||||||
|
f.val = 1
|
||||||
|
} else {
|
||||||
|
f.val /= opand
|
||||||
|
}
|
||||||
|
case '=':
|
||||||
|
f.val = opand
|
||||||
|
}
|
||||||
|
if f.val > f.max {
|
||||||
|
f.val %= f.max
|
||||||
|
}
|
||||||
|
if f.val < f.min {
|
||||||
|
f.val = f.max - f.val%f.max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *point) update(change []parser.Expression, vars map[string]int) {
|
||||||
|
var totalX, totalY, val, opand, max int
|
||||||
|
var target *int
|
||||||
|
|
||||||
|
for i, e := range change {
|
||||||
|
if i == 0 {
|
||||||
|
target = &totalX
|
||||||
|
val = p.x
|
||||||
|
max = p.maxX
|
||||||
|
} else if i == 1 {
|
||||||
|
target = &totalY
|
||||||
|
val = p.y
|
||||||
|
max = p.maxY
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if e.Variable != "" {
|
||||||
|
if val, ok := vars[e.Variable]; ok {
|
||||||
|
opand = val
|
||||||
|
} else {
|
||||||
|
panic(fmt.Sprintf("Runtime error: Encountered unknown variable %q", val))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
opand = e.Opperand
|
||||||
|
}
|
||||||
|
|
||||||
|
switch e.Opperator {
|
||||||
|
case '+':
|
||||||
|
*target = val + opand
|
||||||
|
case '-':
|
||||||
|
*target = val - opand
|
||||||
|
case '*':
|
||||||
|
*target = val * opand
|
||||||
|
case '/':
|
||||||
|
if opand == 0 {
|
||||||
|
*target = 1
|
||||||
|
} else {
|
||||||
|
*target = val / opand
|
||||||
|
}
|
||||||
|
case '=':
|
||||||
|
*target = opand
|
||||||
|
}
|
||||||
|
|
||||||
|
if *target > max {
|
||||||
|
*target %= max
|
||||||
|
}
|
||||||
|
|
||||||
|
if *target < 0 {
|
||||||
|
*target = max - *target%max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.x = totalX
|
||||||
|
p.y = totalY
|
||||||
|
}
|
Loading…
Reference in New Issue