Initial upload

This commit is contained in:
2022-08-24 14:28:45 +02:00
parent c67653ddee
commit 57bc7b0289
370 changed files with 18479 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
{
"blurb": "Implement an evaluator for a very simple subset of Forth",
"authors": [
"leenipper"
],
"contributors": [
"alebaffa",
"bitfield",
"da-edra",
"ekingery",
"ferhatelmas",
"hilary",
"ilmanzo",
"robphoenix",
"sebito91"
],
"files": {
"solution": [
"forth.go"
],
"test": [
"forth_test.go"
],
"example": [
".meta/example.go"
],
"editor": [
"cases_test.go"
]
}
}

View File

@@ -0,0 +1 @@
{"track":"go","exercise":"forth","id":"7fb99fd3f78d43c6a59dd057cac693da","url":"https://exercism.org/tracks/go/exercises/forth","handle":"halfdan","is_requester":true,"auto_approve":false}

40
go/forth/HELP.md Normal file
View File

@@ -0,0 +1,40 @@
# Help
## Running the tests
To run the tests run the command `go test` from within the exercise directory.
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
flags:
go test -v --bench . --benchmem
Keep in mind that each reviewer will run benchmarks on a different machine, with
different specs, so the results from these benchmark tests may vary.
## Submitting your solution
You can submit your solution using the `exercism submit forth.go` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
To get help if you're having trouble, you can use one of the following resources:
- [How to Write Go Code](https://golang.org/doc/code.html)
- [Effective Go](https://golang.org/doc/effective_go.html)
- [Go Resources](http://golang.org/help)
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)

49
go/forth/README.md Normal file
View File

@@ -0,0 +1,49 @@
# Forth
Welcome to Forth on Exercism's Go Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
## Instructions
Implement an evaluator for a very simple subset of Forth.
[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29)
is a stack-based programming language. Implement a very basic evaluator
for a small subset of Forth.
Your evaluator has to support the following words:
- `+`, `-`, `*`, `/` (integer arithmetic)
- `DUP`, `DROP`, `SWAP`, `OVER` (stack manipulation)
Your evaluator also has to support defining new words using the
customary syntax: `: word-name definition ;`.
To keep things simple the only data type you need to support is signed
integers of at least 16 bits size.
You should use the following rules for the syntax: a number is a
sequence of one or more (ASCII) digits, a word is a sequence of one or
more letters, digits, symbols or punctuation that is not a number.
(Forth probably uses slightly different rules, but this is close
enough.)
Words are case-insensitive.
## Source
### Created by
- @leenipper
### Contributed to by
- @alebaffa
- @bitfield
- @da-edra
- @ekingery
- @ferhatelmas
- @hilary
- @ilmanzo
- @robphoenix
- @sebito91

309
go/forth/cases_test.go Normal file
View File

@@ -0,0 +1,309 @@
package forth
// Source: exercism/problem-specifications
// Commit: 75f4c0a Corrected minor typos in the error msg expectation (doesn't match other similar error patterns and so breaks auto generated tests)
// Problem Specifications Version: 1.7.1
type testGroup struct {
group string
tests []testCase
}
type testCase struct {
description string
input []string
expected []int // nil slice indicates error expected.
}
var testGroups = []testGroup{
{
group: "parsing and numbers",
tests: []testCase{
{
"numbers just get pushed onto the stack",
[]string{"1 2 3 4 5"},
[]int{1, 2, 3, 4, 5},
},
},
},
{
group: "addition",
tests: []testCase{
{
"can add two numbers",
[]string{"1 2 +"},
[]int{3},
},
{
"errors if there is nothing on the stack",
[]string{"+"},
[]int(nil),
},
{
"errors if there is only one value on the stack",
[]string{"1 +"},
[]int(nil),
},
},
},
{
group: "subtraction",
tests: []testCase{
{
"can subtract two numbers",
[]string{"3 4 -"},
[]int{-1},
},
{
"errors if there is nothing on the stack",
[]string{"-"},
[]int(nil),
},
{
"errors if there is only one value on the stack",
[]string{"1 -"},
[]int(nil),
},
},
},
{
group: "multiplication",
tests: []testCase{
{
"can multiply two numbers",
[]string{"2 4 *"},
[]int{8},
},
{
"errors if there is nothing on the stack",
[]string{"*"},
[]int(nil),
},
{
"errors if there is only one value on the stack",
[]string{"1 *"},
[]int(nil),
},
},
},
{
group: "division",
tests: []testCase{
{
"can divide two numbers",
[]string{"12 3 /"},
[]int{4},
},
{
"performs integer division",
[]string{"8 3 /"},
[]int{2},
},
{
"errors if dividing by zero",
[]string{"4 0 /"},
[]int(nil),
},
{
"errors if there is nothing on the stack",
[]string{"/"},
[]int(nil),
},
{
"errors if there is only one value on the stack",
[]string{"1 /"},
[]int(nil),
},
},
},
{
group: "combined arithmetic",
tests: []testCase{
{
"addition and subtraction",
[]string{"1 2 + 4 -"},
[]int{-1},
},
{
"multiplication and division",
[]string{"2 4 * 3 /"},
[]int{2},
},
},
},
{
group: "dup",
tests: []testCase{
{
"copies a value on the stack",
[]string{"1 dup"},
[]int{1, 1},
},
{
"copies the top value on the stack",
[]string{"1 2 dup"},
[]int{1, 2, 2},
},
{
"errors if there is nothing on the stack",
[]string{"dup"},
[]int(nil),
},
},
},
{
group: "drop",
tests: []testCase{
{
"removes the top value on the stack if it is the only one",
[]string{"1 drop"},
[]int{},
},
{
"removes the top value on the stack if it is not the only one",
[]string{"1 2 drop"},
[]int{1},
},
{
"errors if there is nothing on the stack",
[]string{"drop"},
[]int(nil),
},
},
},
{
group: "swap",
tests: []testCase{
{
"swaps the top two values on the stack if they are the only ones",
[]string{"1 2 swap"},
[]int{2, 1},
},
{
"swaps the top two values on the stack if they are not the only ones",
[]string{"1 2 3 swap"},
[]int{1, 3, 2},
},
{
"errors if there is nothing on the stack",
[]string{"swap"},
[]int(nil),
},
{
"errors if there is only one value on the stack",
[]string{"1 swap"},
[]int(nil),
},
},
},
{
group: "over",
tests: []testCase{
{
"copies the second element if there are only two",
[]string{"1 2 over"},
[]int{1, 2, 1},
},
{
"copies the second element if there are more than two",
[]string{"1 2 3 over"},
[]int{1, 2, 3, 2},
},
{
"errors if there is nothing on the stack",
[]string{"over"},
[]int(nil),
},
{
"errors if there is only one value on the stack",
[]string{"1 over"},
[]int(nil),
},
},
},
{
group: "user-defined words",
tests: []testCase{
{
"can consist of built-in words",
[]string{": dup-twice dup dup ;", "1 dup-twice"},
[]int{1, 1, 1},
},
{
"execute in the right order",
[]string{": countup 1 2 3 ;", "countup"},
[]int{1, 2, 3},
},
{
"can override other user-defined words",
[]string{": foo dup ;", ": foo dup dup ;", "1 foo"},
[]int{1, 1, 1},
},
{
"can override built-in words",
[]string{": swap dup ;", "1 swap"},
[]int{1, 1},
},
{
"can override built-in operators",
[]string{": + * ;", "3 4 +"},
[]int{12},
},
{
"can use different words with the same name",
[]string{": foo 5 ;", ": bar foo ;", ": foo 6 ;", "bar foo"},
[]int{5, 6},
},
{
"can define word that uses word with the same name",
[]string{": foo 10 ;", ": foo foo 1 + ;", "foo"},
[]int{11},
},
{
"cannot redefine numbers",
[]string{": 1 2 ;"},
[]int(nil),
},
{
"errors if executing a non-existent word",
[]string{"foo"},
[]int(nil),
},
},
},
{
group: "case-insensitivity",
tests: []testCase{
{
"DUP is case-insensitive",
[]string{"1 DUP Dup dup"},
[]int{1, 1, 1, 1},
},
{
"DROP is case-insensitive",
[]string{"1 2 3 4 DROP Drop drop"},
[]int{1},
},
{
"SWAP is case-insensitive",
[]string{"1 2 SWAP 3 Swap 4 swap"},
[]int{2, 3, 4, 1},
},
{
"OVER is case-insensitive",
[]string{"1 2 OVER Over over"},
[]int{1, 2, 1, 2, 1},
},
{
"user-defined words are case-insensitive",
[]string{": foo dup ;", "1 FOO Foo foo"},
[]int{1, 1, 1, 1},
},
{
"definitions are case-insensitive",
[]string{": SWAP DUP Dup dup ;", "1 swap"},
[]int{1, 1, 1, 1},
},
},
},
}

5
go/forth/forth.go Normal file
View File

@@ -0,0 +1,5 @@
package forth
func Forth(input []string) ([]int, error) {
panic("Please implement the Forth function")
}

40
go/forth/forth_test.go Normal file
View File

@@ -0,0 +1,40 @@
package forth
import (
"reflect"
"testing"
)
func TestForth(t *testing.T) {
for _, tg := range testGroups {
for _, tc := range tg.tests {
if v, err := Forth(tc.input); err == nil {
var _ error = err
if tc.expected == nil {
t.Fatalf("FAIL: %s | %s\n\tForth(%#v) expected an error, got %v",
tg.group, tc.description, tc.input, v)
} else if !reflect.DeepEqual(v, tc.expected) {
t.Fatalf("FAIL: %s | %s\n\tForth(%#v) expected %v, got %v",
tg.group, tc.description, tc.input, tc.expected, v)
}
} else if tc.expected != nil {
t.Fatalf("FAIL: %s | %s\n\tForth(%#v) expected %v, got an error: %q",
tg.group, tc.description, tc.input, tc.expected, err)
}
t.Logf("PASS: %s | %s", tg.group, tc.description)
}
}
}
func BenchmarkForth(b *testing.B) {
if testing.Short() {
b.Skip("skipping benchmark in short mode.")
}
for i := 0; i < b.N; i++ {
for _, tg := range testGroups {
for _, tc := range tg.tests {
Forth(tc.input)
}
}
}
}

3
go/forth/go.mod Normal file
View File

@@ -0,0 +1,3 @@
module forth
go 1.16

24
go/forth/stack.go Normal file
View File

@@ -0,0 +1,24 @@
package forth
import "fmt"
type Stack struct {
stack []int
ptr int
}
func (s *Stack) Push(k int) {
s.stack = append(s.stack, k)
}
func (s *Stack) Pop() (int, error) {
if len(s.stack) == 0 {
return 0, fmt.Errorf("cannot pop empty stack")
}
el := s.stack[len(s.stack)-1]
s.stack = s.stack[:len(s.stack)-1]
return el, nil
}