feat: better structured internal
This commit is contained in:
@@ -7,35 +7,37 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.maximhutz.com/max/lambda/internal/cli"
|
"git.maximhutz.com/max/lambda/internal/cli"
|
||||||
|
"git.maximhutz.com/max/lambda/internal/config"
|
||||||
"git.maximhutz.com/max/lambda/pkg/lambda"
|
"git.maximhutz.com/max/lambda/pkg/lambda"
|
||||||
"git.maximhutz.com/max/lambda/pkg/parser"
|
"git.maximhutz.com/max/lambda/pkg/parser"
|
||||||
"git.maximhutz.com/max/lambda/pkg/tokenizer"
|
"git.maximhutz.com/max/lambda/pkg/tokenizer"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Run main application.
|
||||||
func main() {
|
func main() {
|
||||||
|
options, err := config.FromArgs()
|
||||||
options, err := cli.ParseOptions(os.Args[1:])
|
|
||||||
cli.HandleError(err)
|
cli.HandleError(err)
|
||||||
|
|
||||||
logger := cli.GetLogger(*options)
|
logger := options.GetLogger()
|
||||||
logger.Info("Using program arguments.", "args", os.Args)
|
logger.Info("Using program arguments.", "args", os.Args)
|
||||||
logger.Info("Parsed CLI options.", "options", options)
|
logger.Info("Parsed CLI options.", "options", options)
|
||||||
|
|
||||||
if options.Input == "-" {
|
input, err := options.Source.Pull()
|
||||||
options.Input, err = cli.ReadInput()
|
cli.HandleError(err)
|
||||||
cli.HandleError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens, fails := tokenizer.GetTokens([]rune(options.Input))
|
// Parse tokens.
|
||||||
|
tokens, fails := tokenizer.GetTokens([]rune(input))
|
||||||
if len(fails) > 0 {
|
if len(fails) > 0 {
|
||||||
cli.HandleError(errors.Join(fails...))
|
cli.HandleError(errors.Join(fails...))
|
||||||
}
|
}
|
||||||
logger.Info("Parsed tokens.", "tokens", tokens)
|
logger.Info("Parsed tokens.", "tokens", tokens)
|
||||||
|
|
||||||
|
// Turn tokens into syntax tree.
|
||||||
expression, err := parser.GetTree(tokens)
|
expression, err := parser.GetTree(tokens)
|
||||||
cli.HandleError(err)
|
cli.HandleError(err)
|
||||||
logger.Info("Parsed syntax tree.", "tree", lambda.Stringify(expression))
|
logger.Info("Parsed syntax tree.", "tree", lambda.Stringify(expression))
|
||||||
|
|
||||||
|
// Reduce expression.
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
if options.Explanation {
|
if options.Explanation {
|
||||||
|
|||||||
@@ -5,18 +5,24 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Arguments given to program.
|
||||||
type CLIOptions struct {
|
type CLIOptions struct {
|
||||||
Input string
|
// The source code given to the program.
|
||||||
Verbose bool
|
Input string
|
||||||
|
// Whether or not to print debug logs.
|
||||||
|
Verbose bool
|
||||||
|
// Whether or not to print an explanation of the reduction.
|
||||||
Explanation bool
|
Explanation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseOptions(args []string) (*CLIOptions, error) {
|
// Extract the program configuration from the command-line arguments.
|
||||||
// Parse flags and arguments.
|
func ParseOptions() (*CLIOptions, error) {
|
||||||
|
// Parse flags.
|
||||||
verbose := flag.Bool("v", false, "Verbosity. If set, the program will print logs.")
|
verbose := flag.Bool("v", false, "Verbosity. If set, the program will print logs.")
|
||||||
explanation := flag.Bool("x", false, "Explanation. Whether or not to show all reduction steps.")
|
explanation := flag.Bool("x", false, "Explanation. Whether or not to show all reduction steps.")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
// Parse non-flag arguments.
|
||||||
if flag.NArg() == 0 {
|
if flag.NArg() == 0 {
|
||||||
return nil, fmt.Errorf("No input given.")
|
return nil, fmt.Errorf("No input given.")
|
||||||
} else if flag.NArg() > 1 {
|
} else if flag.NArg() > 1 {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// A helper function to handle errors in the program. If it is given an error,
|
||||||
|
// the program will exist, and print the error.
|
||||||
func HandleError(err error) {
|
func HandleError(err error) {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ReadInput() (string, error) {
|
|
||||||
data, err := io.ReadAll(os.Stdin)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
11
internal/config/config.go
Normal file
11
internal/config/config.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
// Arguments given to program.
|
||||||
|
type Config struct {
|
||||||
|
// The source code given to the program.
|
||||||
|
Source Source
|
||||||
|
// Whether or not to print debug logs.
|
||||||
|
Verbose bool
|
||||||
|
// Whether or not to print an explanation of the reduction.
|
||||||
|
Explanation bool
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package cli
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetLogger(o CLIOptions) *slog.Logger {
|
// Define the correct logger for the program to use.
|
||||||
|
func (this Config) GetLogger() *slog.Logger {
|
||||||
var level slog.Level
|
var level slog.Level
|
||||||
if o.Verbose {
|
if this.Verbose {
|
||||||
level = slog.LevelInfo
|
level = slog.LevelInfo
|
||||||
} else {
|
} else {
|
||||||
level = slog.LevelError
|
level = slog.LevelError
|
||||||
35
internal/config/parse_from_args.go
Normal file
35
internal/config/parse_from_args.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Extract the program configuration from the command-line arguments.
|
||||||
|
func FromArgs() (*Config, error) {
|
||||||
|
// Parse flags.
|
||||||
|
verbose := flag.Bool("v", false, "Verbosity. If set, the program will print logs.")
|
||||||
|
explanation := flag.Bool("x", false, "Explanation. Whether or not to show all reduction steps.")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Parse non-flag arguments.
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
return nil, fmt.Errorf("No input given.")
|
||||||
|
} else if flag.NArg() > 1 {
|
||||||
|
return nil, fmt.Errorf("More than 1 command-line argument.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse source type.
|
||||||
|
var source Source
|
||||||
|
if flag.Arg(0) == "-" {
|
||||||
|
source = StdinSource{}
|
||||||
|
} else {
|
||||||
|
source = StringSource{data: flag.Arg(0)}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Config{
|
||||||
|
Source: source,
|
||||||
|
Verbose: *verbose,
|
||||||
|
Explanation: *explanation,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
29
internal/config/source.go
Normal file
29
internal/config/source.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Defines the consumption of different types of input sources.
|
||||||
|
type Source interface {
|
||||||
|
// Get the data.
|
||||||
|
Pull() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A source coming from a string.
|
||||||
|
type StringSource struct{ data string }
|
||||||
|
|
||||||
|
func (this StringSource) Pull() (string, error) { return this.data, nil }
|
||||||
|
|
||||||
|
// A source coming from standard input.
|
||||||
|
type StdinSource struct{}
|
||||||
|
|
||||||
|
func (this StdinSource) Pull() (string, error) {
|
||||||
|
data, err := io.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(data), nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user