~mna/snow unlisted

df88c582d9748238dda46ee3b0c471278d86d04f — Martin Angers 1 year, 1 month ago b80c933
cmd/snowc: implement basic compiler command
6 files changed, 216 insertions(+), 0 deletions(-)

M .gitignore
M .golangci.toml
M cmd/snowc/main.go
M go.mod
M go.sum
A scripts/release.sh
M .gitignore => .gitignore +3 -0
@@ 6,3 6,6 @@

# compiled binary
*.out

# binaries
/bin/

M .golangci.toml => .golangci.toml +7 -0
@@ 27,6 27,13 @@
[issues]
  # regexps of issue texts to exclude
  exclude = [
    # package-level vars for binaries, assigned with linker flags
    "`version` is a global variable",
    "`buildDate` is a global variable",
    # usage variables for command help, constant-like but built with fmt.Sprintf
    "`shortUsage` is a global variable",
    "`longUsage` is a global variable",
    "`commands` is a global variable",
  ]

[[issues.exclude-rules]]

M cmd/snowc/main.go => cmd/snowc/main.go +121 -0
@@ 1,4 1,125 @@
package main

import (
	"context"
	"errors"
	"fmt"
	"os"
	"runtime"
	"syscall"

	"git.sr.ht/~mna/snow/cmd/internal/flag"
	"git.sr.ht/~mna/snow/cmd/internal/mainer"
)

var (
	// placeholder values, replaced on build
	version   = "{v}"
	buildDate = "{d}"
)

const binName = "snowc"

var (
	shortUsage = fmt.Sprintf(`
usage: %s <command> [<path>...]
Run '%[1]s --help' for details.
`, binName)

	longUsage = fmt.Sprintf(`usage: %s <command> [<path>...] [-- <arg>...]
       %[1]s -h|--help
       %[1]s -v|--version

Compiler for the snow programming language.

The <command> can be one of:
	tokenize                  Print the stream of tokens
	parse                     Print the AST
	typecheck                 Print the type-annotated AST
	codegen                   Generate the backend-specific code 
	build                     Invoke the backend compiler to generate a binary or library
	run                       Build and execute the resulting binary

  -h --help                 Show this help
  -v --version              Print version
`, binName)
)

var commands = map[string]func(context.Context, []string) error{
	"tokenize":  nil,
	"parse":     nil,
	"typecheck": nil,
	"codegen":   nil,
	"build":     nil,
	"run":       nil,
}

type cmd struct {
	Help    bool `flag:"h,help" ignored:"true"`
	Version bool `flag:"v,version" ignored:"true"`

	args  []string
	flags map[string]bool
	cmdFn func(context.Context, []string) error

	// for tests only: set a context that will be used as top-level.
	testCtx context.Context
}

func (c *cmd) SetArgs(args []string) {
	c.args = args
}

func (c *cmd) SetFlags(flags map[string]bool) {
	c.flags = flags
}

func (c *cmd) Validate() error {
	if c.Help || c.Version {
		return nil
	}

	if len(c.args) == 0 {
		return errors.New("no command specified")
	}
	c.cmdFn = commands[c.args[0]]
	if c.cmdFn == nil {
		return fmt.Errorf("unknown command: %s", c.args[0])
	}
	return nil
}

func (c *cmd) Main(args []string, stdio *mainer.Stdio) mainer.ExitCode {
	var p flag.Parser
	if err := p.Parse(args, c); err != nil {
		fmt.Fprintf(stdio.Stderr, "invalid arguments: %s\n%s", err, shortUsage)
		return mainer.InvalidArgs
	}

	switch {
	case c.Help:
		fmt.Fprint(stdio.Stdout, longUsage)
		return mainer.Success

	case c.Version:
		fmt.Fprintf(stdio.Stdout, "%s %s %s %s\n", version, buildDate, runtime.GOOS, runtime.GOARCH)
		return mainer.Success
	}

	ctx := context.Background()
	if c.testCtx != nil {
		ctx = c.testCtx
	}
	ctx = mainer.CancelOnSignal(ctx, syscall.SIGINT, syscall.SIGTERM)
	if err := c.cmdFn(ctx, c.args[1:]); err != nil {
		// each command takes care of printing its errors, just return with an error code
		return mainer.Failure
	}

	return mainer.Success
}

func main() {
	var c cmd
	os.Exit(int(c.Main(os.Args, mainer.CurrentStdio())))
}

M go.mod => go.mod +6 -0
@@ 3,8 3,14 @@ module git.sr.ht/~mna/snow
go 1.13

require (
	git.sr.ht/~mna/kick v0.0.0-20191001172206-e3f133a23dd6
	github.com/go-playground/form v3.1.4+incompatible // indirect
	github.com/gorilla/schema v1.1.0
	github.com/hashicorp/go-multierror v1.0.0 // indirect
	github.com/kelseyhightower/envconfig v1.4.0
	github.com/kylelemons/godebug v1.1.0
	github.com/mna/httpparms v0.0.0-20160806173130-30c778d9c13f
	github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 // indirect
	github.com/stretchr/testify v1.4.0
	golang.org/x/exp v0.0.0-20191129062945-2f5052295587
)

M go.sum => go.sum +52 -0
@@ 1,18 1,65 @@
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.sr.ht/~mna/kick v0.0.0-20191001172206-e3f133a23dd6 h1:T/67w/o2VyCZmEHXPVefWI1sPu3oy5HOLzc4yZpny5U=
git.sr.ht/~mna/kick v0.0.0-20191001172206-e3f133a23dd6/go.mod h1:mF4SDjyQVdq2ACU3427/DLdMaYl0gN18/m2BpiuKl/E=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-playground/form v3.1.4+incompatible h1:lvKiHVxE2WvzDIoyMnWcjyiBxKt2+uFJyZcPYWsLnjI=
github.com/go-playground/form v3.1.4+incompatible/go.mod h1:lhcKXfTuhRtIZCIKUeJ0b5F207aeQCPbZU09ScKjwWg=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/csrf v1.5.1 h1:UASc2+EB0T51tvl6/2ls2ciA8/qC7KdTO7DsOEKbttQ=
github.com/gorilla/csrf v1.5.1/go.mod h1:HTDW7xFOO1aHddQUmghe9/2zTvg7AYCnRCs7MxTGu/0=
github.com/gorilla/handlers v1.4.1-0.20190227193432-ac6d24f88de4 h1:jY2wqD6wDOlZGuoaqYD2YqFHc32TsenFpK77lMwuoeU=
github.com/gorilla/handlers v1.4.1-0.20190227193432-ac6d24f88de4/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/juju/ratelimit v1.0.1 h1:+7AIFJVQ0EQgq/K9+0Krm7m530Du7tIz0METWzN0RgY=
github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk=
github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/mna/httpparms v0.0.0-20160806173130-30c778d9c13f h1:vKXfrcbB4Es+O2VDrRMzmK+Ts48vvJ8c755S8/tFTC0=
github.com/mna/httpparms v0.0.0-20160806173130-30c778d9c13f/go.mod h1:5v9sZ8/7GR2Y5iqAJ+5alpa7Wc5Afm3zwBKAb0e6xTs=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7 h1:xoIK0ctDddBMnc74udxJYBqlo9Ylnsp1waqjLsnef20=
github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M=
github.com/sirupsen/logrus v1.4.0 h1:yKenngtzGh+cUSSh6GWbxW2abRqhYUSR/t/6+2QqNvE=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/unrolled/secure v1.0.0 h1:2p4MlT30bNNjaFxA+gtDuLT/73fnXblTC+W/lCzOaZc=
github.com/unrolled/secure v1.0.0/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587 h1:5Uz0rkjCFu9BC9gCRN7EkwVvhNyQgGWb8KNJrPwBoHY=


@@ 22,15 69,20 @@ golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

A scripts/release.sh => scripts/release.sh +27 -0
@@ 0,0 1,27 @@
#!/usr/bin/env bash

set -euo pipefail

function run {
  local pwd=""; pwd=$(pwd)
  if [[ ${pwd} != *snow ]]; then
    echo "must be run from the root of the repository"
    exit 1
  fi

  local tag=""; tag=$(git tag -l --points-at HEAD | head -n 1)
  local hash=""; hash=$(git rev-parse --short HEAD)
  local date=""; date=$(date -u "+%Y-%m-%d+%H:%M:%S")

  for dir in ./cmd/*; do
    local base=""; base=$(basename "${dir}")
    if [[ "${base}" == "internal" ]]; then
      continue
    fi
    if [[ -d "${dir}" ]]; then
      go build -o "bin/${base}" -ldflags "-X main.version=${tag:-${hash}} -X main.buildDate=${date}" "${dir}"
    fi
  done
}

run