scripts are moved to scritps/ directory

This commit is contained in:
Thakee Nathees 2022-05-01 13:26:27 +05:30
parent 962f868907
commit 4e9091b5ec
13 changed files with 299 additions and 116 deletions

View File

@ -8,9 +8,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run check.py script.
- name: Run static checks.
run: |
python3 tests/check.py
python3 scripts/static_check.py
## Compile and run test on linux.
linux-build:
@ -22,7 +22,7 @@ jobs:
make all
- name: Run tests.
run: |
python3 tests/tests.py
python3 scripts/run_tests.py
## Compile and run tests on windows.
windows-build:
@ -31,10 +31,10 @@ jobs:
- uses: actions/checkout@v2
- name: Run build batch script.
run: |
cmd /c build.bat
cmd /c scripts\build.bat
- name: Run tests.
run: |
python3 tests/tests.py
python3 scripts/run_tests.py
## Compile and run tests on macos.
macos-build:
@ -46,6 +46,6 @@ jobs:
make all
- name: Run tests.
run: |
python3 tests/tests.py
python3 scripts/run_tests.py

2
.gitignore vendored
View File

@ -6,7 +6,7 @@
.DS_Store
build/
tests/benchmarks/report.html
scripts/report.html
docs/build/
docs/static/wasm/

View File

@ -9,12 +9,15 @@ RELEASE_CFLAGS = -g -O3
LDFLAGS = -lm
TARGET_EXEC = pocket
BUILD_DIR = ./build
BUILD_DIR = ./build/
SRC_DIRS = ./src ./cli
INC_DIRS = ./src/include
SRC_DIRS = ./src/ ./cli/
INC_DIRS = ./src/include/
SRCS := $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)/*.c))
BIN_DIR = bin/
OBJ_DIR = obj/
SRCS := $(foreach DIR,$(SRC_DIRS),$(wildcard $(DIR)*.c))
OBJS := $(SRCS:.c=.o)
DEPS := $(OBJS:.o=.d)
@ -22,13 +25,13 @@ INC_FLAGS := $(addprefix -I,$(INC_DIRS))
DEP_FLAGS = -MMD -MP
CC_FLAGS = $(INC_FLAGS) $(DEP_FLAGS) $(CFLAGS)
DEBUG_DIR = $(BUILD_DIR)/debug
DEBUG_TARGET = $(DEBUG_DIR)/$(TARGET_EXEC)
DEBUG_OBJS := $(addprefix $(DEBUG_DIR)/, $(OBJS))
DEBUG_DIR = $(BUILD_DIR)Debug/
DEBUG_TARGET = $(DEBUG_DIR)$(BIN_DIR)$(TARGET_EXEC)
DEBUG_OBJS := $(addprefix $(DEBUG_DIR)$(OBJ_DIR), $(OBJS))
RELEASE_DIR = $(BUILD_DIR)/release
RELEASE_TARGET = $(RELEASE_DIR)/$(TARGET_EXEC)
RELEASE_OBJS := $(addprefix $(RELEASE_DIR)/, $(OBJS))
RELEASE_DIR = $(BUILD_DIR)Release/
RELEASE_TARGET = $(RELEASE_DIR)$(BIN_DIR)$(TARGET_EXEC)
RELEASE_OBJS := $(addprefix $(RELEASE_DIR)$(OBJ_DIR), $(OBJS))
.PHONY: debug release all clean
@ -36,18 +39,20 @@ RELEASE_OBJS := $(addprefix $(RELEASE_DIR)/, $(OBJS))
debug: $(DEBUG_TARGET)
$(DEBUG_TARGET): $(DEBUG_OBJS)
@mkdir -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS)
$(DEBUG_DIR)/%.o: %.c
$(DEBUG_DIR)$(OBJ_DIR)%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CC_FLAGS) $(DEBUG_CFLAGS) -c $< -o $@
release: $(RELEASE_TARGET)
$(RELEASE_TARGET): $(RELEASE_OBJS)
@mkdir -p $(dir $@)
$(CC) $^ -o $@ $(LDFLAGS)
$(RELEASE_DIR)/%.o: %.c
$(RELEASE_DIR)$(OBJ_DIR)%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CC_FLAGS) $(RELEASE_CFLAGS) -c $< -o $@

View File

@ -3,9 +3,9 @@
<img src="https://user-images.githubusercontent.com/41085900/161365989-f3fd47bb-7ea7-4114-8e9b-2224e1193079.png" width="500" >
</p>
**Pocketlang** is a small (~3000 semicolons) and [fast](https://github.com/ThakeeNathees/pocketlang#performance)
functional language written in C. It's syntactically similar to Ruby and it can
be learned [within 15 minutes](https://thakeenathees.github.io/pocketlang/docs/v0.1.0/Reference/Cheat-Sheet.html).
**Pocketlang** is a lightweight (~3000 semicolons) and [fast](https://github.com/ThakeeNathees/pocketlang#performance)
object oriented, embeddable scripting language written in C. It has a ruby
flavoured python syntax, that can be learned [within 15 minutes](https://thakeenathees.github.io/pocketlang/docs/v0.1.0/Reference/Cheat-Sheet.html).
Including the compiler, bytecode VM and runtime, it's a standalone executable
with zero external dependencies just as it's self descriptive name. The pocketlang
VM can be embedded in another hosting program very easily.
@ -85,7 +85,7 @@ from [msys2](https://www.msys2.org/) or [cygwin](https://www.cygwin.com/).
#### Windows batch script
```
build
scripts\build.bat
```
You don't have to run the script from a Visual Studio .NET developer command prompt, It'll search
for the MSVS installation path and setup the build environment.
@ -98,7 +98,10 @@ for the MSVS installation path and setup the build environment.
4. Add `src/include` to include path.
5. Compile.
If you weren't able to compile it, please report us by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new).
Visual studio project files can be generated with the premake, see
[scripts/README](https://github.com/ThakeeNathees/pocketlang/scripts/README.md)
for more information. If you weren't able to compile it, please report
us by [opening an issue](https://github.com/ThakeeNathees/pocketlang/issues/new).
## References

View File

@ -30,7 +30,7 @@
#define CLI_NOTICE \
"PocketLang " PK_VERSION_STRING " (https://github.com/ThakeeNathees/pocketlang/)\n" \
"Copyright (c) 2020 - 2021 ThakeeNathees\n" \
"Copyright (c) 2020-2021 ThakeeNathees\n" \
"Copyright (c) 2021-2022 Pocketlang Contributors\n" \
"Free and open source software under the terms of the MIT license.\n"

41
scripts/README.md Normal file
View File

@ -0,0 +1,41 @@
This directory contains all the scripts that were used to build, test, measure
performance etc. pocketlang. These scripts in this directory are path
independent -- can be run from anywhere.
## Using premake
To download the premake **which is only 1.3 MB** stand alone binary, run the
bellow command (on windows it might be `python` and not `python3`) or you
can download it your self at https://premake.github.io/download.
```
python3 download_premake.py
```
It will download and place the `premake.exe` (in windows) binary next to
it, next run the following command to generate Visual studio solution files.
```
premake5 vs2019
```
for other project files and information see: https://premake.github.io/docs/
## Running Benchmarks
Build a release version of the pocketlang (using make file or the build.bat
script) and run the following command to run benchmarks. It'll generate a
benchmark report named `report.html` in this directory.
```
python3 run_benchmarks.py
```
## Other Scripts
`generate_native.py` - will generate the native interface (C extension
for pocketlang) source files from the `pocketlang.h` header. Rest of
the scripts name speak for it self. If you want to add a build script
or found a bug, feel free to open an issue or a PR.

View File

@ -3,7 +3,11 @@
:: Distributed Under The MIT License
@echo off
Pushd "%~dp0"
Pushd %cd%
cd %~dp0
:: Root directory of the project
set pocket_root=%~dp0..\
:: ----------------------------------------------------------------------------
:: PARSE COMMAND LINE ARGS
@ -90,7 +94,7 @@ set addnl_linkflags=/SUBSYSTEM:CONSOLE
set addnl_cdefines=/D_CRT_SECURE_NO_WARNINGS
:: Relative root dir from a single intermediate dir.
set root_dir=..\..\..\
if "%debug_build%"=="false" (
@ -100,11 +104,11 @@ if "%debug_build%"=="false" (
exit /b 1
set cflags=%cflags% -O2 -MD
set target_dir=build\release\
set target_dir=%pocket_root%build\Release\
) else (
set cflags=%cflags% -MDd -ZI
set addnl_cdefines=%addnl_cdefines% /DDEBUG
set target_dir=build\debug\
set target_dir=%pocket_root%build\Debug\
)
if "%shared_lib%"=="true" (
@ -112,43 +116,48 @@ if "%shared_lib%"=="true" (
)
:: Make intermediate folders.
if not exist %target_dir%src\ md %target_dir%src\
if not exist %target_dir%cli\ md %target_dir%cli\
if not exist %target_dir%bin\ md %target_dir%bin\
if not exist %target_dir%bin\ mkdir %target_dir%bin\
if not exist %target_dir%lib\ mkdir %target_dir%lib\
if not exist %target_dir%obj\pocket mkdir %target_dir%obj\pocket\
if not exist %target_dir%obj\cli\ mkdir %target_dir%obj\cli\
:: ----------------------------------------------------------------------------
:: COMPILE
:: ----------------------------------------------------------------------------
:COMPILE
:: Go inside src\ build all src files.
cd %target_dir%src\
cl /nologo /c %addnl_cdefines% %addnl_cflags% %root_dir%src\*.c
cd %target_dir%obj\pocket
cl /nologo /c %addnl_cdefines% %addnl_cflags% %pocket_root%src\*.c
if errorlevel 1 goto :FAIL
:: If compiling shared lib, jump pass the lib/cli binaries.
if "%shared_lib%"=="true" (
set pklib=..\bin\pocket-dll.lib
set pklib=%target_dir%bin\pocket.lib
) else (
set pklib=..\bin\pocket.lib
set pklib=%target_dir%lib\pocket.lib
)
:: If compiling shared lib, jump pass the lib/cli binaries.
if "%shared_lib%"=="true" goto :SHARED
lib /nologo %addnl_linkflags% /OUT:%pklib% *.obj
goto :SRC_END
:SHARED
link /nologo /dll /out:..\bin\pocket.dll /implib:%pklib% *.obj
link /nologo /dll /out:%target_dir%bin\pocket.dll /implib:%pklib% *.obj
:SRC_END
if errorlevel 1 goto :FAIL
:: Go inside cli\ from src\ build all cli files.
cd ..\cli\
cl /nologo /c %addnl_cdefines% %addnl_cflags% /I%root_dir%src\include\ %root_dir%cli\*.c
cd %target_dir%obj\cli
cl /nologo /c %addnl_cdefines% %addnl_cflags% /I%pocket_root%src\include\ %pocket_root%cli\*.c
if errorlevel 1 goto :FAIL
cd %target_dir%bin\
:: Compile the cli executable.
cl /nologo %addnl_cdefines% *.obj %pklib% /Fe..\bin\pocket.exe
cl /nologo %addnl_cdefines% %target_dir%obj\cli\*.obj %pklib% /Fe%target_dir%bin\pocket.exe
if errorlevel 1 goto :FAIL
:: Navigate to the build directory.
@ -162,8 +171,8 @@ goto :SUCCESS
:CLEAN
if exist "build/debug" rmdir /S /Q "build/debug"
if exist "build/release" rmdir /S /Q "build/release"
if exist "%pocket_root%build/Debug" rmdir /S /Q "%pocket_root%build/Debug"
if exist "%pocket_root%build/Release" rmdir /S /Q "%pocket_root%build/Release"
echo.
echo Files were cleaned.
@ -179,9 +188,10 @@ echo Compilation Success
goto :END
:FAIL
popd
endlocal
echo Build failed. See the error messages.
exit /b 1
goto :END
:END
popd

View File

@ -0,0 +1,48 @@
##
## Copyright (c) 2020-2022 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License
##
## A tiny script to download and place premake binary in this path.
## Primarly used to generate Visual Studio project files. Feel free
## add other build script and platforms.
import urllib.request
import os, platform
import tempfile, zipfile, tarfile
from os.path import abspath, dirname, join
THIS_PATH = abspath(dirname(__file__))
PREMAKE_PLATFORM_URL = {
"Windows": "https://github.com/premake/premake-core/releases/download/v5.0.0-beta1/premake-5.0.0-beta1-windows.zip",
#"Linux": TODO,
#"Darwin": TODO,
}
def main():
system = platform.system()
if system not in PREMAKE_PLATFORM_URL:
error_exit(f"Platform {system} is currently not supported.\n" +\
"(You can modify this script to add your platform and contribute).")
premake_url = PREMAKE_PLATFORM_URL[system]
tmpdir = tempfile.mkdtemp()
zip_path = join(tmpdir, 'premake5.zip')
with urllib.request.urlopen(premake_url) as binary_zip:
with open(zip_path, 'wb') as f:
f.write(binary_zip.read())
premake_zip = zipfile.ZipFile(zip_path, 'r')
premake_zip.extractall(THIS_PATH)
print("premake5 downloaded successfully.")
## prints an error message to stderr and exit immediately.
def error_exit(msg):
print("Error:", msg, file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()

View File

@ -3,6 +3,9 @@
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License
raise Exception("The paths of the files should be fixed "
"after this script is moved to scripts/ directory.")
import re, os
from os.path import (join, exists, abspath,
relpath, dirname)

80
scripts/premake5.lua Normal file
View File

@ -0,0 +1,80 @@
--
-- Copyright (c) 2020-2022 Thakee Nathees
-- Copyright (c) 2021-2022 Pocketlang Contributors
-- Distributed Under The MIT License
--
-- Requires premake5.0.0-alpha-12 or greater.
local build_dir = "../build/"
local src_dir = "../src/"
local cli_dir = "../cli/"
workspace "pocketlang"
location (build_dir)
configurations { "Debug", "Release" }
platforms { "x86", "x64" }
filter "platforms:x86"
architecture "x86"
filter "platforms:x64"
architecture "x64"
-- Reusable project configurations.
function proj_commons(target_dir)
language "C"
cdialect "C99"
objdir (build_dir .. "%{cfg.buildcfg}/obj/")
targetdir (build_dir .. "%{cfg.buildcfg}/" .. target_dir)
filter "configurations:Debug"
defines { "DEBUG" }
symbols "On"
filter "configurations:Release"
defines { "NDEBUG" }
optimize "On"
filter "system:Windows"
staticruntime "On"
systemversion "latest"
postbuildcommands ""
defines { "_CRT_SECURE_NO_WARNINGS" }
filter {}
end
-- pocketlang sources as static library.
project "pocket_static"
kind "StaticLib"
targetname "pocket"
proj_commons("lib/")
files { src_dir .. "*.c",
src_dir .. "**.h"}
-- pocketlang sources as shared library.
project "pocket_shared"
kind "SharedLib"
targetname "pocket"
proj_commons("bin/")
files { src_dir .. "*.c",
src_dir .. "**.h"}
defines { "PK_DLL", "PK_COMPILE" }
-- command line executable.
project "pocket_cli"
kind "ConsoleApp"
targetname "pocket"
proj_commons("bin/")
files { cli_dir .. "*.c",
cli_dir .. "**.h" }
includedirs ({ src_dir .. "include/" })
links { "pocket_static" }

View File

@ -8,11 +8,17 @@ import subprocess, platform
from shutil import which
from os.path import join, abspath, dirname, relpath, exists
## The absolute path of this file, when run as a script.
## This file is not intended to be included in other files at the moment.
## Absolute path of this file's directory.
THIS_PATH = abspath(dirname(__file__))
## A list of benchmark directories, relative to THIS_PATH
## Output debug cli executable's directory.
POCKET_BINARY_DIR = abspath(join(THIS_PATH, "../build/Release/bin/"))
## Pocket lang root directory. All the listed paths bellow are relative to
## the BENCHMARKS_DIR.
BENCHMARKS_DIR = abspath(join(THIS_PATH, "../tests/benchmarks"))
## A list of benchmark directories, relative to BENCHMARKS_DIR
BENCHMARKS = (
"factors",
"fib",
@ -34,23 +40,6 @@ INTERPRETERS = {
#'javascript' : ('node', '.js'),
}
## Map from systems to the relative pocket binary path.
SYSTEM_TO_POCKET_PATH = {
"current" : {
"Windows": "..\\..\\build\\release\\bin\\pocket.exe",
"Linux" : "../../build/release/pocket",
"Darwin" : "../../build/release/pocket",
},
## This maps the older version of pocket in the system path, to compare
## pocketlang with it's older version.
"older" : {
"Windows": "..\\..\\build\\release\\bin\\pocket_older.exe",
"Linux" : "../../build/release/pocket_older",
"Darwin" : "../../build/release/pocket_older",
}
}
## The html template to display the report.
HTML_TEMPLATE = "template.html"
@ -63,7 +52,7 @@ def main():
print_title(benchmark.title())
for lang in INTERPRETERS:
interp, ext = INTERPRETERS[lang]
source = abspath(join(THIS_PATH, benchmark, benchmark + ext))
source = abspath(join(BENCHMARKS_DIR, benchmark, benchmark + ext))
if not exists(source): continue
print(" %-10s : "%lang, end=''); sys.stdout.flush()
result = subprocess.run([interp, source],
@ -78,27 +67,32 @@ def main():
display_results(results)
## This will return the path of the pocket binary (on different platforms).
## The debug version of it for enabling the assertions.
def get_pocket_binary(name, fail):
system = platform.system()
if system not in ("Windows", "Linux", "Darwin"):
error_exit("Unsupported platform")
binary = join(POCKET_BINARY_DIR, name)
if system == "Windows": binary += ".exe"
if not exists(binary):
if fail: error_exit(f"Pocket interpreter not found at: '{binary}'")
else: return None
return binary
## Set the pocketlang path for the current system to the compiled output.
def update_interpreters():
system = platform.system()
if system not in SYSTEM_TO_POCKET_PATH['current']:
print("Unsupported platform %s" % system)
sys.exit(1)
pocket = get_pocket_binary("pocket", True)
pocket_older = get_pocket_binary("pocket_older", False)
global INTERPRETERS
pocket = abspath(join(THIS_PATH, SYSTEM_TO_POCKET_PATH['current'][system]))
pocket_older = abspath(join(THIS_PATH, SYSTEM_TO_POCKET_PATH['older'][system]))
if not exists(pocket):
print(f"{colmsg('Error', COL_RED)}: " +
"Pocket interpreter not found at: '%s'" % pocket)
sys.exit(1)
INTERPRETERS['pocketlang'] = (pocket, '.pk')
## Add if older version of pocketlang if exists.
if exists(pocket_older):
if pocket_older is not None:
INTERPRETERS['pk-older'] = (pocket_older, '.pk')
if 'python' in INTERPRETERS and system == "Windows":
if 'python' in INTERPRETERS and platform.system() == "Windows":
INTERPRETERS['python'] = ('python', '.py')
missing = []
@ -241,6 +235,11 @@ def print_title(title):
print(" %s " % title)
_print_sep()
## prints an error message to stderr and exit immediately.
def error_exit(msg):
print("Error:", msg, file=sys.stderr)
sys.exit(1)
## Simple color logger --------------------------------------------------------
## https://stackoverflow.com/a/70599663/10846399

View File

@ -5,15 +5,18 @@
import os, sys, platform
import subprocess, json, re
from os.path import join, abspath, dirname, relpath
from os.path import (join, abspath, dirname,
relpath, exists)
## TODO: Re-write this in doctest (https://github.com/onqtam/doctest)
## The absolute path of this file, when run as a script.
## This file is not intended to be included in other files at the moment.
THIS_PATH = abspath(dirname(__file__))
## Pocket lang root directory.
ROOT_PATH = abspath(join(dirname(__file__), ".."))
## All the test files.
## Output debug cli executable path relative to root.
POCKET_BINARY = "build/Debug/bin/pocket"
## All the test files, relative to root/tests/ directory.
TEST_SUITE = {
"Unit Tests": (
"lang/basics.pk",
@ -49,13 +52,6 @@ TEST_SUITE = {
),
}
## Map from systems to the relative binary path
SYSTEM_TO_BINARY_PATH = {
"Windows": "..\\build\\debug\\bin\\pocket.exe",
"Linux": "../build/debug/pocket",
"Darwin": "../build/debug/pocket",
}
## This global variable will be set to true if any test failed.
tests_failed = False
@ -71,7 +67,7 @@ def run_all_tests():
for suite in TEST_SUITE:
print_title(suite)
for test in TEST_SUITE[suite]:
path = join(THIS_PATH, test)
path = join(ROOT_PATH, "tests", test)
run_test_file(pocket, test, path)
def run_test_file(pocket, test, path):
@ -94,14 +90,13 @@ def run_test_file(pocket, test, path):
## The debug version of it for enabling the assertions.
def get_pocket_binary():
system = platform.system()
if system not in SYSTEM_TO_BINARY_PATH:
error_exit("Unsupported platform %s" % system)
pocket = abspath(join(THIS_PATH, SYSTEM_TO_BINARY_PATH[system]))
if not os.path.exists(pocket):
error_exit("Pocket interpreter not found at: '%s'" % pocket)
return pocket
if system not in ("Windows", "Linux", "Darwin"):
error_exit("Unsupported platform")
binary = join(ROOT_PATH, POCKET_BINARY)
if system == "Windows": binary += ".exe"
if not exists(binary):
error_exit(f"Pocket interpreter not found at: '{binary}'")
return binary
def run_command(command):
return subprocess.run(command,
@ -136,8 +131,7 @@ def print_success(msg):
for line in msg.splitlines():
print(COLORS['GREEN'] + line + COLORS['END'])
## prints an error message to stderr and exit
## immediately.
## prints an error message to stderr and exit immediately.
def error_exit(msg):
print("Error:", msg, file=sys.stderr)
sys.exit(1)

View File

@ -10,15 +10,15 @@ import os, sys, re
from os import listdir
from os.path import join, abspath, dirname, relpath, normpath
## The absolute path of this file, when run as a script.
## This file is not intended to be included in other files at the moment.
THIS_PATH = abspath(dirname(__file__))
## Pocket lang root directory. All the listed paths bellow are relative to
## the root path.
ROOT_PATH = abspath(join(dirname(__file__), ".."))
## A list of source files, to check if the fnv1a hash values match it's
## corresponding cstring in the CASE_ATTRIB(name, hash) macro calls.
HASH_CHECK_LIST = [
"../src/pk_core.c",
"../src/pk_value.c",
"src/pk_core.c",
"src/pk_value.c",
]
## A list of extension to perform static checks, of all the files in the
@ -31,19 +31,19 @@ ALLOW_LONG_LINES = ('http://', 'https://', '<script ', '<link ', '<svg ')
## A list of files that are allowed to be longer than 79 characters.
ALLOW_LONG_FILES = (
"../cli/native.py",
"../cli/modules/pknative.gen.c",
"cli/native.py",
"cli/modules/pknative.gen.c",
)
## A list of directory, contains C source files to perform static checks.
## This will include all files with extension from CHECK_EXTENTIONS.
SOURCE_DIRS = [
"../src/",
"../cli/",
"../cli/modules/",
"src/",
"cli/",
"cli/modules/",
"../docs/",
"../docs/wasm/",
"docs/",
"docs/wasm/",
]
## This global variable will be set to true if any check failed.
@ -52,12 +52,12 @@ checks_failed = False
## Converts a list of relative paths from the working directory
## to a list of relative paths from this file's absolute directory.
def to_abs_paths(sources):
return map(lambda s: os.path.join(THIS_PATH, s), sources)
return map(lambda s: os.path.join(ROOT_PATH, s), sources)
## Converts the path from absolute path to relative path from the
## toplelve of the project.
def to_rel_path(path):
return relpath(path, join(THIS_PATH, '..'))
return relpath(path, ROOT_PATH)
def main():
check_fnv1_hash(to_abs_paths(HASH_CHECK_LIST))
@ -126,7 +126,7 @@ def check_static(dirs):
break
for ignore in ALLOW_LONG_FILES:
## TODO: the bellow normpath(join()) should be calcuated once.
if curr_file == normpath(join(THIS_PATH, ignore)):
if curr_file == normpath(join(ROOT_PATH, ignore)):
skip = True
break
if skip: continue