diff --git a/.github/workflows/snek.yml b/.github/workflows/snek.yml index 69b6f02..067c9f7 100644 --- a/.github/workflows/snek.yml +++ b/.github/workflows/snek.yml @@ -26,7 +26,7 @@ jobs: docker run --rm \ --mount type=bind,source=`pwd`/artifacts,destination=/artifacts \ snek \ - make DESTDIR=/artifacts PREFIX=/opt/snek check install + make DESTDIR=/artifacts PREFIX=/opt/snek SNEK_RISCV_TEST=1 check install - name: 'Upload results' uses: actions/upload-artifact@v2 diff --git a/Makefile b/Makefile index 7274d6d..e47c9b2 100644 --- a/Makefile +++ b/Makefile @@ -36,35 +36,9 @@ FORCE: check: all +cd test && make $@ - +black --check --exclude 'fail-syntax-.*\.py' . + +black --check --exclude 'fail-syntax-.*\.py|.*/hosts/.*.py' . -SHAREFILES = \ - snek.defs \ - $(SNEK_SRC) \ - $(SNEK_EXT_SRC) \ - $(SNEK_RAW_INC) \ - $(SNEK_EXT_INC) \ - $(SNEK_BUILTINS) \ - $(SNEK_EXT_BUILTINS) \ - $(SNEK_ROOT)/snek-gram.ll \ - $(SNEK_ROOT)/snek-builtin.py - -IMAGEFILES = \ - snek.svg - -DOCFILES = \ - $(IMAGEFILES) - -PKGFILES = \ - snek.pc - -install: $(SHAREFILES) $(PKGFILES) $(DOCFILES) - install -d $(DESTDIR)$(SHAREDIR) - for i in $(SHAREFILES); do install --mode=644 "$$i" $(DESTDIR)$(SHAREDIR) || exit 1; done - install -d $(DESTDIR)$(PKGCONFIG) - for i in $(PKGFILES); do install --mode=644 "$$i" $(DESTDIR)$(PKGCONFIG) || exit 1; done - install -d $(DESTDIR)$(DOCDIR) - for i in $(DOCFILES); do install --mode=644 "$$i" $(DESTDIR)$(DOCDIR) || exit 1; done +install: +for dir in $(SUBDIRS); do (cd $$dir && make PREFIX=$(PREFIX) DESTDIR=$(DESTDIR) $@) || exit 1; done +for snek in $(SNEKS); do (cd `dirname $$snek` && make PREFIX=$(PREFIX) DESTDIR=$(DESTDIR) $@) || exit 1; done @@ -76,9 +50,6 @@ otheros: $(SNEKS) +cd doc && make +for otheros in $(SNEK_OTHEROS_DIR); do (cd "$$otheros" && make); done -snek.pc: snek.pc.in - $(SNEK_SED) $^ > $@ - snek-mu.py: find . -name '*.builtin' -print0 | xargs -0 python3 ./snek-builtin.py --mu -o $@ @@ -86,6 +57,5 @@ docker: docker build -t phsilva/snek . clean: - rm -f snek.pc +for dir in $(SUBDIRS); do (cd $$dir && make PREFIX=$(PREFIX) DESTDIR=$(DESTDIR) $@); done +for snek in $(SNEKS); do (cd `dirname $$snek` && make PREFIX=$(PREFIX) DESTDIR=$(DESTDIR) $@); done diff --git a/chips/avr/snek-avr.defs b/chips/avr/snek-avr.defs index d099784..5c9d7a1 100644 --- a/chips/avr/snek-avr.defs +++ b/chips/avr/snek-avr.defs @@ -56,7 +56,8 @@ CFLAGS = $(AVR_CFLAGS) $(SNEK_CFLAGS) LDSCRIPT=$(SNEK_AVR)/snek-avr51.x -LDFLAGS=-Wl,-uvfprintf -lprintf_flt -lm \ +LDFLAGS=$(SNEK_LDFLAGS) \ + -Wl,-uvfprintf -lprintf_flt -lm \ -Wl,--defsym -Wl,__TEXT_REGION_LENGTH__=0x8000 \ -Wl,--defsym -Wl,__DATA_REGION_LENGTH__=0x880 \ -Wl,--defsym -Wl,__EEPROM_REGION_LENGTH__=0x400 \ diff --git a/chips/qemu/snek-qemu.defs b/chips/qemu/snek-qemu.defs index 87e3125..84d51fb 100644 --- a/chips/qemu/snek-qemu.defs +++ b/chips/qemu/snek-qemu.defs @@ -40,7 +40,7 @@ CFLAGS=$(ARCH_CFLAGS) --oslib=semihost \ -std=gnu99 $(OPT) -g \ -I. -I$(SNEK_QEMU) -I$(SNEK_ROOT) $(PICOLIBC_CFLAGS) $(SNEK_CFLAGS) -LDFLAGS=$(CFLAGS) -n +LDFLAGS=$(SNEK_LDFLAGS) $(CFLAGS) -n LIBS=-lm diff --git a/chips/samd21/snek-samd21.defs b/chips/samd21/snek-samd21.defs index c51ba38..3f34eea 100644 --- a/chips/samd21/snek-samd21.defs +++ b/chips/samd21/snek-samd21.defs @@ -81,7 +81,7 @@ CFLAGS = $(SAMD21_CFLAGS) $(SNEK_CFLAGS) LDSCRIPT=$(SNEK_SAMD21)/snek-samd21.ld -LDFLAGS=$(CFLAGS) -Wl,-T$(SNEK_SAMD21)/registers.ld -T$(LDSCRIPT) -n +LDFLAGS=$(SNEK_LDFLAGS) $(CFLAGS) -Wl,-T$(SNEK_SAMD21)/registers.ld -T$(LDSCRIPT) -n LIBS=-lm diff --git a/hosts/macosx/Makefile b/hosts/macosx/Makefile index b16a151..1cec439 100644 --- a/hosts/macosx/Makefile +++ b/hosts/macosx/Makefile @@ -64,7 +64,7 @@ snek-bits: $(SNEK_FILES) macosx cp -p $(SNEK_SCRIPTS) macosx/snek.app/Contents/MacOS/ endif -$(MACOSX_DIST): $(MACOSX_FILES) macosx +$(MACOSX_DIST): $(MACOSX_FILES) macosx snek-bits rm -f $@ cp -a $(MACOSX_DOCS) macosx cp -a $(MACOSX_INSTALL) macosx diff --git a/hosts/macosx/build-mac b/hosts/macosx/build-mac index 980f305..189181b 100755 --- a/hosts/macosx/build-mac +++ b/hosts/macosx/build-mac @@ -28,12 +28,13 @@ esac build="$1" builddir=`echo $build | sed 's/^[^:]*://'` +buildhost=`echo $build | sed 's/:.*$//'` echo builddir "$builddir" target="$2" rsync -Ravz --delete `git ls-files` "$build" -ssh imac-remote "cd '$builddir'/ports/posix && make" +ssh $buildhost "cd '$builddir'/ports/posix && make" rsync -avz "$build"/ports/posix/snek "$curdir"/"$target" diff --git a/ports/duemilanove/Makefile b/ports/duemilanove/Makefile index 2f0f0e1..98cd30b 100644 --- a/ports/duemilanove/Makefile +++ b/ports/duemilanove/Makefile @@ -44,7 +44,8 @@ CC=avr-gcc OPT=-Os -frename-registers -funsigned-char -fno-jump-tables -mcall-prologues CFLAGS=$(OPT) -DF_CPU=16000000UL -mmcu=atmega328p -I. -I$(SNEK_LOCAL_VPATH) -g $(SNEK_CFLAGS) -Waddr-space-convert -LDFLAGS=-Wl,-uvfprintf -lprintf_flt -lm \ +LDFLAGS=$(SNEK_LDFLAGS) \ + -Wl,-uvfprintf -lprintf_flt -lm \ -Wl,--defsym -Wl,__TEXT_REGION_LENGTH__=0x7e00 \ -Wl,--defsym -Wl,__DATA_REGION_LENGTH__=0x7a0 \ -Wl,--defsym -Wl,__EEPROM_REGION_LENGTH__=0x400 \ diff --git a/ports/duemilanove/snek-duemilanove-install.1 b/ports/duemilanove/snek-duemilanove-install.1 index c998ce1..84fcbcb 100644 --- a/ports/duemilanove/snek-duemilanove-install.1 +++ b/ports/duemilanove/snek-duemilanove-install.1 @@ -23,8 +23,8 @@ Duemilanove board. .SH OPTIONS .TP \-isp -Specifies the programmer to use, common options are 'optiboot', -'usbtiny', and 'avrisp2'. The default is 'optiboot'. +Specifies the programmer to use, common options are optiboot, +usbtiny, and avrisp2. The default is optiboot. .TP \-hex Specifies the hex file to load to the board. The default is the diff --git a/ports/esp32/.gitignore b/ports/esp32/.gitignore index d054d84..f04d3d5 100644 --- a/ports/esp32/.gitignore +++ b/ports/esp32/.gitignore @@ -1,3 +1,4 @@ build sdkconfig sdkconfig.old +*.bin diff --git a/ports/esp32/Makefile b/ports/esp32/Makefile index 47db7fe..28d98e9 100644 --- a/ports/esp32/Makefile +++ b/ports/esp32/Makefile @@ -12,7 +12,8 @@ # General Public License for more details. # -include ../../snek.defs +SNEK_ROOT = ../.. +include ../../snek-install.defs ESP32_IDF ?= ./esp32-idf @@ -37,3 +38,7 @@ load: connect: minicom -D /dev/ttyUSB1 -b 115200 + +install: $(TARGET) + install -d $(DESTDIR)$(SHAREDIR) + install -m 0644 $(TARGET) $(DESTDIR)$(SHAREDIR) diff --git a/ports/hifive1revb/Makefile b/ports/hifive1revb/Makefile index 5338f77..31ba670 100644 --- a/ports/hifive1revb/Makefile +++ b/ports/hifive1revb/Makefile @@ -63,7 +63,7 @@ HIFIVE1REVB_CFLAGS=-march=rv32imac -mabi=ilp32 \ CFLAGS = $(HIFIVE1REVB_CFLAGS) $(SNEK_CFLAGS) $(AO_CFLAGS) -LDFLAGS=$(CFLAGS) -n -Wl,--gc-sections +LDFLAGS=$(SNEK_LDFLAGS) $(CFLAGS) -n LIBS=-lm diff --git a/ports/mega/Makefile b/ports/mega/Makefile index fb39d81..7b21278 100644 --- a/ports/mega/Makefile +++ b/ports/mega/Makefile @@ -48,7 +48,8 @@ HEX=$(BASE).hex MAP=$(BASE).map CC=avr-gcc CFLAGS=-Os -DF_CPU=16000000UL -mmcu=atmega2560 -I. -I$(SNEK_LOCAL_VPATH) -g -fno-jump-tables $(SNEK_CFLAGS) -mcall-prologues -Waddr-space-convert -LDFLAGS=-Wl,-uvfprintf -lprintf_flt -lm \ +LDFLAGS=$(SNEK_LDFLAGS) \ + -Wl,-uvfprintf -lprintf_flt -lm \ -Wl,--defsym -Wl,__TEXT_REGION_LENGTH__=0x3e000 \ -Wl,--defsym -Wl,__DATA_REGION_LENGTH__=0x1e00 \ -Wl,--defsym -Wl,__EEPROM_REGION_LENGTH__=0x1000 \ diff --git a/ports/posix/snek-main.c b/ports/posix/snek-main.c index e6465c3..b778397 100644 --- a/ports/posix/snek-main.c +++ b/ports/posix/snek-main.c @@ -21,7 +21,7 @@ FILE *snek_posix_input; static const struct option options[] = { { .name = "version", .has_arg = 0, .val = 'v' }, - { .name = "file", .has_arg = 1, .val = 'f' }, + { .name = "interactive", .has_arg = 0, .val = 'i' }, { .name = "help", .has_arg = 0, .val = '?' }, { .name = NULL, .has_arg = 0, .val = 0 }, }; @@ -29,7 +29,7 @@ static const struct option options[] = { static void usage (char *program, int val) { - fprintf(stderr, "usage: %s [--version] [--help] [--file ] \n", program); + fprintf(stderr, "usage: %s [--version] [--help] [--interactive] \n", program); exit(val); } @@ -71,16 +71,17 @@ int main (int argc, char **argv) { int c; - char *file = NULL; + bool do_interactive = true; + bool interactive_flag = false; - while ((c = getopt_long(argc, argv, "v?f:", options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "v?i", options, NULL)) != -1) { switch (c) { case 'v': printf("%s version %s\n", argv[0], SNEK_VERSION); exit(0); break; - case 'f': - file = optarg; + case 'i': + interactive_flag = true; break; case '?': usage(argv[0], 0); @@ -93,15 +94,7 @@ main (int argc, char **argv) snek_init(); - if (file) { - snek_file = file; - snek_posix_input = fopen(snek_file, "r"); - if (!snek_posix_input) { - perror(snek_file); - exit(1); - } - snek_parse(); - } + bool ret = true; if (argv[optind]) { snek_file = argv[optind]; @@ -110,18 +103,21 @@ main (int argc, char **argv) perror(snek_file); exit(1); } - } else { + if (snek_parse() != snek_parse_success) + ret = false; + fclose(snek_posix_input); + do_interactive = interactive_flag; + } + + if (do_interactive) { + printf("Welcome to Snek version %s\n", SNEK_VERSION); snek_file = ""; snek_posix_input = stdin; snek_interactive = true; - printf("Welcome to Snek version %s\n", SNEK_VERSION); + if (snek_parse() != snek_parse_success) + ret = false; + printf("\n"); } - bool ret = snek_parse() == snek_parse_success; - - if (snek_posix_input == stdin) - printf("\n"); - else - fclose(snek_posix_input); return ret ? 0 : 1; } diff --git a/ports/posix/snek.1 b/ports/posix/snek.1 index 94237a2..5632856 100644 --- a/ports/posix/snek.1 +++ b/ports/posix/snek.1 @@ -15,14 +15,29 @@ .SH NAME snek \- Snek Programming Language .SH SYNOPSIS -.B "snek" {program.py} +.B "snek" [--version|-v] [--help|-?] [--interactive|-i] [program.py] .SH DESCRIPTION .I snek is a small Python-derivative suitable for embedded computers. This host version is largely designed to help test the Snek system and applications on larger machines +.SH COMMAND LINE OPTIONS +.TP +\--version or \-v +Reports the version number to stdout and then exits. +.TP +\--help or \-? +Prints usage information to stdout and then exits. +.TP +\--interactive or \-i +When a program is specified on the command line, enter interactive +mode after executing that program. .SH USAGE -If you specify a program file on the command line, snek will load and -execute this instead of reading from the command line. +When a program is specified on the command line, snek runs it. Then, +if the --interactive flag is passed, it enters interactive +mode. Otherwise, it exits. +.P +When no program is specified on the command line, snek enters +interactive mode. .SH AUTHOR Keith Packard diff --git a/snek-list.c b/snek-list.c index 52b7e74..4d6d0a4 100644 --- a/snek-list.c +++ b/snek-list.c @@ -280,7 +280,7 @@ snek_list_imm(snek_offset_t size, snek_list_type_t type) s -= 2; snek_poly_t key = snek_stack_pick(s+1); snek_poly_t value = snek_stack_pick(s); - snek_poly_t *ref = _snek_list_ref(list, key, false, true); + snek_poly_t *ref = _snek_list_ref(list, key, true, true); if (ref) *ref = value; } diff --git a/snek-poly.c b/snek-poly.c index c557f6f..7b60c78 100644 --- a/snek-poly.c +++ b/snek-poly.c @@ -84,11 +84,13 @@ snek_poly_cmp(snek_poly_t a, snek_poly_t b, bool is) int8_t tdiff = atype - btype; if (tdiff) return tdiff; + int sdiff; switch (atype) { case snek_float: return (b.f < a.f) - (a.f < b.f); case snek_string: - return strcmp(snek_poly_to_string(a), snek_poly_to_string(b)); + sdiff = strcmp(snek_poly_to_string(a), snek_poly_to_string(b)); + return (sdiff > 0) - (sdiff < 0); case snek_list: if (!is) return snek_list_cmp(snek_poly_to_list(a), snek_poly_to_list(b)); diff --git a/snek.defs b/snek.defs index 699e229..e51df64 100644 --- a/snek.defs +++ b/snek.defs @@ -7,11 +7,13 @@ vpath %.ll $(SNEK_LOCAL_VPATH):$(SNEK_ROOT) vpath %.py $(SNEK_LOCAL_VPATH):$(SNEK_ROOT) vpath %.builtin $(SNEK_LOCAL_VPATH):$(SNEK_ROOT) -SNEK_VERSION = 1.4 -SNEK_DATE = 2020-05-13 +SNEK_VERSION = 1.4.1 +SNEK_DATE = 2020-05-22 SNEK_VERSION_DASH = $(shell echo $(SNEK_VERSION) | sed 's/\./-/g') +SNEK_CLANG = $(shell if $(CC) --version | grep -q -i llvm; then echo yes; else echo no; fi) + SNEK_PORTS = $(SNEK_ROOT)/ports SNEK_HOSTS = $(SNEK_ROOT)/hosts SNEK_DOC = $(SNEK_ROOT)/doc @@ -79,19 +81,25 @@ SNEK_MOST_WARNINGS = \ -Wmissing-prototypes \ -Wmissing-declarations \ -Wnested-externs \ - -Warray-bounds=2 \ -Wshadow +ifeq ($(SNEK_CLANG),yes) +SNEK_MOST_WARNINGS += -Warray-bounds +else +SNEK_MOST_WARNINGS += -Warray-bounds=2 +endif + SNEK_WARNINGS = \ $(SNEK_MOST_WARNINGS) \ -Wimplicit-fallthrough SNEK_BASE_CFLAGS = \ - -Wl,--gc-sections \ -D_DEFAULT_SOURCE \ -I$(SNEK_ROOT) $(SNEK_LOCAL_CFLAGS) \ -DSNEK_VERSION='"$(SNEK_VERSION)"' +SNEK_LDFLAGS = -Wl,--gc-sections + SNEK_CFLAGS ?= $(SNEK_WARNINGS) $(SNEK_BASE_CFLAGS) SNEK_SED = sed \ diff --git a/snek.pc.in b/snek.pc.in deleted file mode 100644 index 2f9ded8..0000000 --- a/snek.pc.in +++ /dev/null @@ -1,6 +0,0 @@ -sneklib=@SNEKLIB@ - -Name: snek -Description: Snek. A tiny python-esque language -Version: @SNEK_VERSION@ -Cflags: -I${sneklib} diff --git a/test/Makefile b/test/Makefile index ea8493b..ad69a28 100644 --- a/test/Makefile +++ b/test/Makefile @@ -18,10 +18,14 @@ include $(SNEK_ROOT)/snek.defs PYTHON3?=python3 SNEK_NATIVE?=$(SNEK_PORTS)/posix/snek +ifdef SNEK_RISCV_TEST SNEK_RISCV?=$(SNEK_PORTS)/qemu-riscv/snek-riscv +else +SNEK_RISCV= +endif SNEK_ARM?=$(SNEK_PORTS)/qemu-arm/snek-arm -LANGS=python3 $(SNEK_NATIVE) $(SNEK_ARM) +LANGS=python3 $(SNEK_NATIVE) $(SNEK_ARM) $(SNEK_RISCV) SUCCESS_TESTS = \ pass-andor.py \ @@ -72,6 +76,7 @@ FAIL_TESTS = \ fail-interpolate-missing.py \ fail-interpolate-extra.py \ fail-interpolate-badformat.py \ + fail-dictionary-mutable.py \ $(SYNTAX_TESTS) check: diff --git a/test/fail-dictionary-mutable.py b/test/fail-dictionary-mutable.py new file mode 100644 index 0000000..bb3e3cf --- /dev/null +++ b/test/fail-dictionary-mutable.py @@ -0,0 +1,14 @@ +# +# Copyright © 2020 Keith Packard +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +a = {{"hello": "world"}: "foo"}