Module sverchok.utils.modules.profile_mk3.parser
Expand source code
# ##### BEGIN GPL LICENSE BLOCK #####
#
# 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 2
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
import re
from sverchok.utils.parsec import *
from sverchok.utils.sv_logging import sv_logger
from sverchok.utils.modules.profile_mk3.interpreter import *
#########################################
# DSL parsing
#########################################
# Compare these definitions with BNF definition at the top of profile_mk3.py.
expr_regex = re.compile(r"({[^}]+})\s*", re.DOTALL)
def parse_expr(src):
for string, rest in parse_regexp(expr_regex)(src):
expr = Expression.from_string(string)
if expr is not None:
yield expr, rest
identifier_regexp = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
parse_semicolon = parse_word(";")
def parse_identifier(src):
for (name, _), rest in sequence(parse_regexp(identifier_regexp), parse_whitespace)(src):
yield name, rest
def parse_negated_variable(src):
for (_, name, _), rest in sequence(parse_word("-"), parse_regexp(identifier_regexp), parse_whitespace)(src):
yield NegatedVariable(name), rest
def parse_value(src):
for smth, rest in one_of(parse_number, parse_identifier, parse_negated_variable, parse_expr)(src):
if isinstance(smth, (int, float)):
yield Const(smth), rest
elif isinstance(smth, str):
yield Variable(smth), rest
else:
yield smth, rest
def parse_pair(src):
parser = sequence(parse_value, parse_word(","), parse_value)
for (x, _, y), rest in parser(src):
yield (x,y), rest
def parse_letter(absolute, relative):
def parser(src):
for smth, rest in one_of(parse_word(absolute), parse_word(relative))(src):
is_abs = smth == absolute
yield is_abs, rest
return parser
def parse_MoveTo(src):
parser = sequence(parse_letter("M", "m"), parse_pair, optional(parse_semicolon))
for (is_abs, (x, y), _), rest in parser(src):
yield MoveTo(is_abs, x, y), rest
def parse_LineTo(src):
parser = sequence(
parse_letter("L", "l"),
many(parse_pair),
optional(parse_parameter("n")),
optional(parse_word("z")),
optional(parse_semicolon))
for (is_abs, pairs, num_segments, z, _), rest in parser(src):
yield LineTo(is_abs, pairs, num_segments, z is not None), rest
def parse_parameter(name):
def parser(src):
for (_, _, value), rest in sequence(parse_word(name), parse_word("="), parse_value)(src):
yield value, rest
return parser
def parse_CurveTo(src):
def parse_segment(src):
parser = sequence(parse_pair, parse_pair, parse_pair)
for (control1, control2, knot2), rest in parser(src):
yield CurveTo.Segment(control1, control2, knot2), rest
parser = sequence(
parse_letter("C", "c"),
many(parse_segment),
optional(parse_parameter("n")),
optional(parse_word("z")),
optional(parse_semicolon)
)
for (is_abs, segments, num_segments, z, _), rest in parser(src):
yield CurveTo(is_abs, segments, num_segments, z is not None), rest
def parse_SmoothCurveTo(src):
def parse_segment(src):
parser = sequence(parse_pair, parse_pair)
for (control2, knot2), rest in parser(src):
yield SmoothCurveTo.Segment(control2, knot2), rest
parser = sequence(
parse_letter("S", "s"),
many(parse_segment),
optional(parse_parameter("n")),
optional(parse_word("z")),
optional(parse_semicolon)
)
for (is_abs, segments, num_segments, z, _), rest in parser(src):
yield SmoothCurveTo(is_abs, segments, num_segments, z is not None), rest
def parse_QuadCurveTo(src):
def parse_segment(src):
parser = sequence(parse_pair, parse_pair)
for (control, knot2), rest in parser(src):
yield QuadraticCurveTo.Segment(control, knot2), rest
parser = sequence(
parse_letter("Q", "q"),
many(parse_segment),
optional(parse_parameter("n")),
optional(parse_word("z")),
optional(parse_semicolon)
)
for (is_abs, segments, num_segments, z, _), rest in parser(src):
yield QuadraticCurveTo(is_abs, segments, num_segments, z is not None), rest
def parse_SmoothQuadCurveTo(src):
def parse_segment(src):
for knot2, rest in parse_pair(src):
yield SmoothQuadraticCurveTo.Segment(knot2), rest
parser = sequence(
parse_letter("T", "t"),
many(parse_segment),
optional(parse_parameter("n")),
optional(parse_word("z")),
optional(parse_semicolon)
)
for (is_abs, knot2, num_segments, z, _), rest in parser(src):
yield SmoothQuadraticCurveTo(is_abs, knot2, num_segments, z is not None), rest
def parse_ArcTo(src):
parser = sequence(
parse_letter("A", "a"),
parse_pair,
parse_value,
parse_value,
parse_value,
parse_pair,
optional(parse_parameter("n")),
optional(parse_word("z")),
optional(parse_semicolon)
)
for (is_abs, radii, rot, flag1, flag2, end, num_verts, z, _), rest in parser(src):
yield ArcTo(is_abs, radii, rot, flag1, flag2, end, num_verts, z is not None), rest
def parse_HorLineTo(src):
# NB: H/h command MUST end with semicolon, otherwise we will not be able to
# understand where it ends, i.e. does the following letter begin a new statement
# or is it just next X value denoted by variable.
parser = sequence(parse_letter("H", "h"),
many(parse_value, backtracking=True),
optional(parse_parameter("n")),
parse_semicolon)
for (is_abs, xs, num_segments, _), rest in parser(src):
yield HorizontalLineTo(is_abs, xs, num_segments), rest
def parse_VertLineTo(src):
# NB: V/v command MUST end with semicolon, otherwise we will not be able to
# understand where it ends, i.e. does the following letter begin a new statement
# or is it just next X value denoted by variable.
parser = sequence(parse_letter("V", "v"),
many(parse_value, backtracking=True),
optional(parse_parameter("n")),
parse_semicolon)
for (is_abs, ys, num_segments, _), rest in parser(src):
yield VerticalLineTo(is_abs, ys, num_segments), rest
def parse_Interpolate(src):
parser = sequence(
parse_letter("@I", "@i"),
optional(parse_word("@smooth")),
parse_value,
many(parse_pair, backtracking=True),
optional(parse_parameter("n")),
optional(parse_word("z")),
parse_semicolon)
for (is_abs, smooth, degree, points, num_segments, z, _), rest in parser(src):
yield InterpolatedCurveTo(is_abs, degree, points, num_segments, 'DISTANCE', smooth is not None, z is not None), rest
parse_CloseAll = parse_word("X", CloseAll())
parse_ClosePath = parse_word("x", ClosePath())
def parse_Default(src):
parser = sequence(
parse_word("default"),
parse_identifier,
parse_word("="),
parse_value,
optional(parse_semicolon)
)
for (_, name, _, value, _), rest in parser(src):
yield Default(name, value), rest
def parse_Assign(src):
parser = sequence(
parse_word("let"),
parse_identifier,
parse_word("="),
parse_value,
optional(parse_semicolon)
)
for (_, name, _, value, _), rest in parser(src):
yield Assign(name, value), rest
parse_statement = one_of(
parse_Default,
parse_Assign,
parse_MoveTo,
parse_LineTo,
parse_HorLineTo,
parse_VertLineTo,
parse_CurveTo,
parse_SmoothCurveTo,
parse_QuadCurveTo,
parse_SmoothQuadCurveTo,
parse_ArcTo,
parse_Interpolate,
parse_ClosePath,
parse_CloseAll
)
parse_definition = many(parse_statement)
def parse_profile(src):
# Strip comments
# (hope no one uses # in expressions)
cleaned = ""
for line in src.split("\n"):
comment_idx = line.find('#')
if comment_idx != -1:
line = line[:comment_idx]
cleaned = cleaned + " " + line
profile = parse(parse_definition, cleaned)
sv_logger.debug(profile)
return profile
Functions
def parse_ArcTo(src)
-
Expand source code
def parse_ArcTo(src): parser = sequence( parse_letter("A", "a"), parse_pair, parse_value, parse_value, parse_value, parse_pair, optional(parse_parameter("n")), optional(parse_word("z")), optional(parse_semicolon) ) for (is_abs, radii, rot, flag1, flag2, end, num_verts, z, _), rest in parser(src): yield ArcTo(is_abs, radii, rot, flag1, flag2, end, num_verts, z is not None), rest
def parse_Assign(src)
-
Expand source code
def parse_Assign(src): parser = sequence( parse_word("let"), parse_identifier, parse_word("="), parse_value, optional(parse_semicolon) ) for (_, name, _, value, _), rest in parser(src): yield Assign(name, value), rest
def parse_CurveTo(src)
-
Expand source code
def parse_CurveTo(src): def parse_segment(src): parser = sequence(parse_pair, parse_pair, parse_pair) for (control1, control2, knot2), rest in parser(src): yield CurveTo.Segment(control1, control2, knot2), rest parser = sequence( parse_letter("C", "c"), many(parse_segment), optional(parse_parameter("n")), optional(parse_word("z")), optional(parse_semicolon) ) for (is_abs, segments, num_segments, z, _), rest in parser(src): yield CurveTo(is_abs, segments, num_segments, z is not None), rest
def parse_Default(src)
-
Expand source code
def parse_Default(src): parser = sequence( parse_word("default"), parse_identifier, parse_word("="), parse_value, optional(parse_semicolon) ) for (_, name, _, value, _), rest in parser(src): yield Default(name, value), rest
def parse_HorLineTo(src)
-
Expand source code
def parse_HorLineTo(src): # NB: H/h command MUST end with semicolon, otherwise we will not be able to # understand where it ends, i.e. does the following letter begin a new statement # or is it just next X value denoted by variable. parser = sequence(parse_letter("H", "h"), many(parse_value, backtracking=True), optional(parse_parameter("n")), parse_semicolon) for (is_abs, xs, num_segments, _), rest in parser(src): yield HorizontalLineTo(is_abs, xs, num_segments), rest
def parse_Interpolate(src)
-
Expand source code
def parse_Interpolate(src): parser = sequence( parse_letter("@I", "@i"), optional(parse_word("@smooth")), parse_value, many(parse_pair, backtracking=True), optional(parse_parameter("n")), optional(parse_word("z")), parse_semicolon) for (is_abs, smooth, degree, points, num_segments, z, _), rest in parser(src): yield InterpolatedCurveTo(is_abs, degree, points, num_segments, 'DISTANCE', smooth is not None, z is not None), rest
def parse_LineTo(src)
-
Expand source code
def parse_LineTo(src): parser = sequence( parse_letter("L", "l"), many(parse_pair), optional(parse_parameter("n")), optional(parse_word("z")), optional(parse_semicolon)) for (is_abs, pairs, num_segments, z, _), rest in parser(src): yield LineTo(is_abs, pairs, num_segments, z is not None), rest
def parse_MoveTo(src)
-
Expand source code
def parse_MoveTo(src): parser = sequence(parse_letter("M", "m"), parse_pair, optional(parse_semicolon)) for (is_abs, (x, y), _), rest in parser(src): yield MoveTo(is_abs, x, y), rest
def parse_QuadCurveTo(src)
-
Expand source code
def parse_QuadCurveTo(src): def parse_segment(src): parser = sequence(parse_pair, parse_pair) for (control, knot2), rest in parser(src): yield QuadraticCurveTo.Segment(control, knot2), rest parser = sequence( parse_letter("Q", "q"), many(parse_segment), optional(parse_parameter("n")), optional(parse_word("z")), optional(parse_semicolon) ) for (is_abs, segments, num_segments, z, _), rest in parser(src): yield QuadraticCurveTo(is_abs, segments, num_segments, z is not None), rest
def parse_SmoothCurveTo(src)
-
Expand source code
def parse_SmoothCurveTo(src): def parse_segment(src): parser = sequence(parse_pair, parse_pair) for (control2, knot2), rest in parser(src): yield SmoothCurveTo.Segment(control2, knot2), rest parser = sequence( parse_letter("S", "s"), many(parse_segment), optional(parse_parameter("n")), optional(parse_word("z")), optional(parse_semicolon) ) for (is_abs, segments, num_segments, z, _), rest in parser(src): yield SmoothCurveTo(is_abs, segments, num_segments, z is not None), rest
def parse_SmoothQuadCurveTo(src)
-
Expand source code
def parse_SmoothQuadCurveTo(src): def parse_segment(src): for knot2, rest in parse_pair(src): yield SmoothQuadraticCurveTo.Segment(knot2), rest parser = sequence( parse_letter("T", "t"), many(parse_segment), optional(parse_parameter("n")), optional(parse_word("z")), optional(parse_semicolon) ) for (is_abs, knot2, num_segments, z, _), rest in parser(src): yield SmoothQuadraticCurveTo(is_abs, knot2, num_segments, z is not None), rest
def parse_VertLineTo(src)
-
Expand source code
def parse_VertLineTo(src): # NB: V/v command MUST end with semicolon, otherwise we will not be able to # understand where it ends, i.e. does the following letter begin a new statement # or is it just next X value denoted by variable. parser = sequence(parse_letter("V", "v"), many(parse_value, backtracking=True), optional(parse_parameter("n")), parse_semicolon) for (is_abs, ys, num_segments, _), rest in parser(src): yield VerticalLineTo(is_abs, ys, num_segments), rest
def parse_expr(src)
-
Expand source code
def parse_expr(src): for string, rest in parse_regexp(expr_regex)(src): expr = Expression.from_string(string) if expr is not None: yield expr, rest
def parse_identifier(src)
-
Expand source code
def parse_identifier(src): for (name, _), rest in sequence(parse_regexp(identifier_regexp), parse_whitespace)(src): yield name, rest
def parse_letter(absolute, relative)
-
Expand source code
def parse_letter(absolute, relative): def parser(src): for smth, rest in one_of(parse_word(absolute), parse_word(relative))(src): is_abs = smth == absolute yield is_abs, rest return parser
def parse_negated_variable(src)
-
Expand source code
def parse_negated_variable(src): for (_, name, _), rest in sequence(parse_word("-"), parse_regexp(identifier_regexp), parse_whitespace)(src): yield NegatedVariable(name), rest
def parse_pair(src)
-
Expand source code
def parse_pair(src): parser = sequence(parse_value, parse_word(","), parse_value) for (x, _, y), rest in parser(src): yield (x,y), rest
def parse_parameter(name)
-
Expand source code
def parse_parameter(name): def parser(src): for (_, _, value), rest in sequence(parse_word(name), parse_word("="), parse_value)(src): yield value, rest return parser
def parse_profile(src)
-
Expand source code
def parse_profile(src): # Strip comments # (hope no one uses # in expressions) cleaned = "" for line in src.split("\n"): comment_idx = line.find('#') if comment_idx != -1: line = line[:comment_idx] cleaned = cleaned + " " + line profile = parse(parse_definition, cleaned) sv_logger.debug(profile) return profile
def parse_value(src)
-
Expand source code
def parse_value(src): for smth, rest in one_of(parse_number, parse_identifier, parse_negated_variable, parse_expr)(src): if isinstance(smth, (int, float)): yield Const(smth), rest elif isinstance(smth, str): yield Variable(smth), rest else: yield smth, rest