mirror of
https://codeberg.org/scip/rpnc.git
synced 2025-12-17 20:41:01 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64e66e9d7b | ||
|
|
23a4d87514 | ||
|
|
2ce8cc7a7e | ||
|
|
e963a770a7 | ||
|
|
ad2d9d98d6 | ||
|
|
bb49cb7626 |
4
Makefile
4
Makefile
@@ -57,8 +57,8 @@ test:
|
||||
go test -v ./...
|
||||
|
||||
singletest:
|
||||
@echo "Call like this: ''make singletest TEST=TestPrepareColumns MOD=lib"
|
||||
go test -run $(TEST) github.com/tlinden/rpn/$(MOD)
|
||||
@echo "Call like this: ''make singletest TEST=TestPrepareColumns"
|
||||
go test -run $(TEST)
|
||||
|
||||
cover-report:
|
||||
go test ./... -cover -coverprofile=coverage.out
|
||||
|
||||
@@ -15,10 +15,17 @@ Features:
|
||||
- various stack manipulation commands
|
||||
- basic math operators
|
||||
- advanced math functions (not yet complete)
|
||||
- provides interactive repl
|
||||
- can be used on the commandline
|
||||
- can calculate data in batch mode (also from STDIN)
|
||||
- extensible with custom LUA functions
|
||||
- provides interactive repl
|
||||
- completion
|
||||
- history
|
||||
- comments (comment character is `#`)
|
||||
|
||||
## Demo
|
||||
|
||||

|
||||
|
||||
## Working principle
|
||||
|
||||
|
||||
28
calc.go
28
calc.go
@@ -32,11 +32,13 @@ type Calc struct {
|
||||
debug bool
|
||||
batch bool
|
||||
stdin bool
|
||||
showstack bool
|
||||
stack *Stack
|
||||
history []string
|
||||
completer readline.AutoCompleter
|
||||
interpreter *Interpreter
|
||||
Space *regexp.Regexp
|
||||
Comment *regexp.Regexp
|
||||
Constants []string
|
||||
LuaFunctions []string
|
||||
|
||||
@@ -48,6 +50,7 @@ type Calc struct {
|
||||
const Help string = `Available commands:
|
||||
batch toggle batch mode
|
||||
debug toggle debug output
|
||||
show show the last 5 items of the stack
|
||||
dump display the stack contents
|
||||
clear clear the whole stack
|
||||
shift remove the last element of the stack
|
||||
@@ -81,7 +84,7 @@ median median of all values`
|
||||
// commands, constants and operators, defined here to feed completion
|
||||
// and our mode switch in Eval() dynamically
|
||||
const (
|
||||
Commands string = `dump reverse debug undebug clear batch shift undo help history manual exit quit swap`
|
||||
Commands string = `dump reverse debug undebug clear batch shift undo help history manual exit quit swap show`
|
||||
Constants string = `Pi Phi Sqrt2 SqrtE SqrtPi SqrtPhi Ln2 Log2E Ln10 Log10E`
|
||||
)
|
||||
|
||||
@@ -131,6 +134,7 @@ func NewCalc() *Calc {
|
||||
)
|
||||
|
||||
c.Space = regexp.MustCompile(`\s+`)
|
||||
c.Comment = regexp.MustCompile(`#.*`) // ignore everything after #
|
||||
|
||||
// pre-calculate mode switching arrays
|
||||
c.Constants = strings.Split(Constants, " ")
|
||||
@@ -162,14 +166,21 @@ func (c *Calc) ToggleStdin() {
|
||||
c.stdin = !c.stdin
|
||||
}
|
||||
|
||||
func (c *Calc) ToggleShow() {
|
||||
c.showstack = !c.showstack
|
||||
}
|
||||
|
||||
func (c *Calc) Prompt() string {
|
||||
p := "\033[31m»\033[0m "
|
||||
b := ""
|
||||
|
||||
if c.batch {
|
||||
b = "->batch"
|
||||
}
|
||||
|
||||
d := ""
|
||||
v := ""
|
||||
|
||||
if c.debug {
|
||||
d = "->debug"
|
||||
v = fmt.Sprintf("/rev%d", c.stack.rev)
|
||||
@@ -180,7 +191,8 @@ func (c *Calc) Prompt() string {
|
||||
|
||||
// the actual work horse, evaluate a line of calc command[s]
|
||||
func (c *Calc) Eval(line string) {
|
||||
line = strings.TrimSpace(line)
|
||||
// remove surrounding whitespace and comments, if any
|
||||
line = strings.TrimSpace(c.Comment.ReplaceAllString(line, ""))
|
||||
|
||||
if line == "" {
|
||||
return
|
||||
@@ -271,6 +283,8 @@ func (c *Calc) Eval(line string) {
|
||||
for _, entry := range c.history {
|
||||
fmt.Println(entry)
|
||||
}
|
||||
case "show":
|
||||
c.ToggleShow()
|
||||
case "exit":
|
||||
fallthrough
|
||||
case "quit":
|
||||
@@ -282,6 +296,16 @@ func (c *Calc) Eval(line string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.showstack && !c.stdin {
|
||||
dots := ""
|
||||
|
||||
if c.stack.Len() > 5 {
|
||||
dots = "... "
|
||||
}
|
||||
last := c.stack.Last(5)
|
||||
fmt.Printf("stack: %s%s\n", dots, list2str(last))
|
||||
}
|
||||
}
|
||||
|
||||
// Execute a math function, check if it is defined just in case
|
||||
|
||||
73
calc_test.go
73
calc_test.go
@@ -22,6 +22,79 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCommentsAndWhitespace(t *testing.T) {
|
||||
calc := NewCalc()
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
cmd []string
|
||||
exp float64 // last element of the stack
|
||||
}{
|
||||
{
|
||||
name: "whitespace prefix",
|
||||
cmd: []string{" 5"},
|
||||
exp: 5.0,
|
||||
},
|
||||
{
|
||||
name: "whitespace postfix",
|
||||
cmd: []string{"5 "},
|
||||
exp: 5.0,
|
||||
},
|
||||
{
|
||||
name: "whitespace both",
|
||||
cmd: []string{" 5 "},
|
||||
exp: 5.0,
|
||||
},
|
||||
{
|
||||
name: "comment line w/ spaces",
|
||||
cmd: []string{"5", " # 19"},
|
||||
exp: 5.0,
|
||||
},
|
||||
{
|
||||
name: "comment line w/o spaces",
|
||||
cmd: []string{"5", `#19`},
|
||||
exp: 5.0,
|
||||
},
|
||||
{
|
||||
name: "inline comment w/ spaces",
|
||||
cmd: []string{"5 # 19"},
|
||||
exp: 5.0,
|
||||
},
|
||||
{
|
||||
name: "inline comment w/o spaces",
|
||||
cmd: []string{"5#19"},
|
||||
exp: 5.0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
testname := fmt.Sprintf("%s .(expect %.2f)",
|
||||
tt.name, tt.exp)
|
||||
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
for _, line := range tt.cmd {
|
||||
calc.Eval(line)
|
||||
}
|
||||
got := calc.stack.Last()
|
||||
|
||||
if len(got) > 0 {
|
||||
if got[0] != tt.exp {
|
||||
t.Errorf("parsing failed:\n+++ got: %f\n--- want: %f",
|
||||
got, tt.exp)
|
||||
}
|
||||
}
|
||||
|
||||
if calc.stack.Len() != 1 {
|
||||
t.Errorf("invalid stack size:\n+++ got: %d\n--- want: 1",
|
||||
calc.stack.Len())
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
calc.stack.Clear()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalc(t *testing.T) {
|
||||
calc := NewCalc()
|
||||
|
||||
|
||||
7
demo/Makefile
Normal file
7
demo/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
#
|
||||
|
||||
|
||||
all:
|
||||
asciinema rec --cols 80 --row 25 -c "env - PS1='> ' PATH=..:$PATH /bin/bash --norc --noprofile" --overwrite demo.cast
|
||||
agg demo.cast demo.gif
|
||||
|
||||
3
demo/demo.cast
Normal file
3
demo/demo.cast
Normal file
@@ -0,0 +1,3 @@
|
||||
{"version": 2, "width": 80, "height": 25, "timestamp": 1699358215, "env": {"SHELL": "/bin/bash", "TERM": "tmux-256color"}}
|
||||
[0.005628, "o", "> "]
|
||||
[0.941195, "o", "exit\r\n"]
|
||||
BIN
demo/demo.gif
Normal file
BIN
demo/demo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 613 KiB |
18
demo/sessions.txt
Normal file
18
demo/sessions.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
# demo sessions, used to create an interactive rpn recording
|
||||
|
||||
# part 1: interactive
|
||||
|
||||
# put some numbers onto the stack
|
||||
2 4 6
|
||||
8
|
||||
10
|
||||
|
||||
# take a look at the stack
|
||||
dump
|
||||
|
||||
# add the last 2
|
||||
+
|
||||
|
||||
# multiply the result and the previous
|
||||
*
|
||||
|
||||
4
main.go
4
main.go
@@ -30,7 +30,7 @@ import (
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
)
|
||||
|
||||
const VERSION string = "2.0.2"
|
||||
const VERSION string = "2.0.4"
|
||||
|
||||
const Usage string = `This is rpn, a reverse polish notation calculator cli.
|
||||
|
||||
@@ -39,6 +39,7 @@ Usage: rpn [-bdvh] [<operator>]
|
||||
Options:
|
||||
-b, --batchmode enable batch mode
|
||||
-d, --debug enable debug mode
|
||||
-s, --stack show last 5 items of the stack (off by default)
|
||||
-m, --manual show manual
|
||||
-v, --version show version
|
||||
-h, --help show help
|
||||
@@ -58,6 +59,7 @@ func main() {
|
||||
configfile := ""
|
||||
|
||||
flag.BoolVarP(&calc.batch, "batchmode", "b", false, "batch mode")
|
||||
flag.BoolVarP(&calc.showstack, "showstack", "s", false, "show stack")
|
||||
flag.BoolVarP(&enabledebug, "debug", "d", false, "debug mode")
|
||||
flag.BoolVarP(&showversion, "version", "v", false, "show version")
|
||||
flag.BoolVarP(&showhelp, "help", "h", false, "show usage")
|
||||
|
||||
48
rpn.go
48
rpn.go
@@ -111,7 +111,9 @@ DESCRIPTION
|
||||
switch or debug toggle command), then the backup stack is also being
|
||||
displayed.
|
||||
|
||||
The stack can be reversed using the reverse command.
|
||||
The stack can be reversed using the reverse command. However, sometimes
|
||||
only the last two values are in the wrong order. Use the swap command to
|
||||
exchange them.
|
||||
|
||||
You can use the shift command to remove the last number from the stack.
|
||||
|
||||
@@ -145,8 +147,52 @@ DESCRIPTION
|
||||
log10 log1p log2 logb pow round roundtoeven sin sinh tan tanh trunc y0
|
||||
y1 copysign dim hypot
|
||||
|
||||
Commands:
|
||||
|
||||
batch toggle batch mode
|
||||
debug toggle debug output
|
||||
dump display the stack contents
|
||||
clear clear the whole stack
|
||||
shift remove the last element of the stack
|
||||
reverse reverse the stack elements
|
||||
swap exchange the last two stack elements
|
||||
show show the last 5 items of the stack
|
||||
history display calculation history
|
||||
help|? show this message
|
||||
quit|exit|c-d|c-c exit program
|
||||
|
||||
Refer to https://pkg.go.dev/math for details about those functions.
|
||||
|
||||
INTERACTIVE REPL
|
||||
While you can use rpn in the command-line, the best experience you'll
|
||||
have is the interactive repl (read eval print loop). Just execute "rpn"
|
||||
and you'll be there.
|
||||
|
||||
In interactive mode you can use TAB completion to complete commands,
|
||||
operators and functions. There's also a history, which allows you to
|
||||
repeat complicated calculations (as long as you've entered them in one
|
||||
line).
|
||||
|
||||
There are also a lot of key bindings, here are the most important ones:
|
||||
|
||||
ctrl-c + ctrl-d
|
||||
Exit interactive rpn
|
||||
|
||||
ctrl-z
|
||||
Send rpn to the backgound.
|
||||
|
||||
ctrl-a
|
||||
Beginning of line.
|
||||
|
||||
ctrl-e
|
||||
End of line.
|
||||
|
||||
ctrl-l
|
||||
Clear the screen.
|
||||
|
||||
ctrl-r
|
||||
Search through history.
|
||||
|
||||
EXTENDING RPN USING LUA
|
||||
You can use a lua script with lua functions to extend the calculator. By
|
||||
default the tool looks for "~/.rpn.lua". You can also specify a script
|
||||
|
||||
67
rpn.pod
67
rpn.pod
@@ -154,8 +154,75 @@ Math functions:
|
||||
log10 log1p log2 logb pow round roundtoeven sin sinh tan tanh trunc y0
|
||||
y1 copysign dim hypot
|
||||
|
||||
Commands:
|
||||
|
||||
batch toggle batch mode
|
||||
debug toggle debug output
|
||||
dump display the stack contents
|
||||
clear clear the whole stack
|
||||
shift remove the last element of the stack
|
||||
reverse reverse the stack elements
|
||||
swap exchange the last two stack elements
|
||||
show show the last 5 items of the stack
|
||||
history display calculation history
|
||||
help|? show this message
|
||||
quit|exit|c-d|c-c exit program
|
||||
|
||||
|
||||
Refer to https://pkg.go.dev/math for details about those functions.
|
||||
|
||||
=head1 INTERACTIVE REPL
|
||||
|
||||
While you can use rpn in the command-line, the best experience you'll
|
||||
have is the interactive repl (read eval print loop). Just execute
|
||||
C<rpn> and you'll be there.
|
||||
|
||||
In interactive mode you can use TAB completion to complete commands,
|
||||
operators and functions. There's also a history, which allows you to
|
||||
repeat complicated calculations (as long as you've entered them in one
|
||||
line).
|
||||
|
||||
There are also a lot of key bindings, here are the most important
|
||||
ones:
|
||||
|
||||
=over
|
||||
|
||||
=item ctrl-c + ctrl-d
|
||||
|
||||
Exit interactive rpn
|
||||
|
||||
=item ctrl-z
|
||||
|
||||
Send rpn to the backgound.
|
||||
|
||||
=item ctrl-a
|
||||
|
||||
Beginning of line.
|
||||
|
||||
=item ctrl-e
|
||||
|
||||
End of line.
|
||||
|
||||
=item ctrl-l
|
||||
|
||||
Clear the screen.
|
||||
|
||||
=item ctrl-r
|
||||
|
||||
Search through history.
|
||||
|
||||
=back
|
||||
|
||||
=head1 COMMENTS
|
||||
|
||||
Lines starting with C<#> are being ignored as comments. You can also
|
||||
append comments to rpn input, e.g.:
|
||||
|
||||
# a comment
|
||||
123 # another comment
|
||||
|
||||
In this case only 123 will be added to the stack.
|
||||
|
||||
=head1 EXTENDING RPN USING LUA
|
||||
|
||||
You can use a lua script with lua functions to extend the
|
||||
|
||||
Reference in New Issue
Block a user