Backend for parameteriztion with thingiverse like syntax

This commit is contained in:
amarjeetkapoor1 2016-07-24 02:31:11 +05:30
parent 9519cc9939
commit 02b3079aee
12 changed files with 747 additions and 10 deletions

View file

@ -235,6 +235,36 @@ win* {
YACCSOURCES += src/parser.y
}
FLEX = src/comment_lexer.l
BISON = src/comment_parser.y
flexs.name = Flex ${QMAKE_FILE_IN}
flexs.input = FLEX
flexs.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.cpp
flexs.commands = flex -o${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_IN}
flexs.CONFIG += target_predeps
flexs.variable_out = GENERATED_SOURCES
silent:flexs.commands = @echo Lex ${QMAKE_FILE_IN} && $$flexs.commands
QMAKE_EXTRA_COMPILERS += flexs
bison.name = Bison ${QMAKE_FILE_IN}
biso.input = BISON
biso.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.cpp
biso.commands = bison -d -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_IN}
biso.commands += && if [[ -e ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}_yacc.hpp ]] ; then mv ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.hpp ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.h ; fi
biso.CONFIG += target_predeps
biso.variable_out = GENERATED_SOURCES
silent:biso.commands = @echo Bison ${QMAKE_FILE_IN} && $$biso.commands
QMAKE_EXTRA_COMPILERS += biso
biso_header.input = BISON
biso_header.output = ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.h
biso_header.commands = bison -d -o ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.cpp ${QMAKE_FILE_IN}
biso_header.commands += && if [ -e ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.hpp ]; then mv ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.hpp ${QMAKE_FILE_PATH}/${QMAKE_FILE_BASE}.h ; fi
biso_header.CONFIG += target_predeps no_link
silent:biso_header.commands = @echo Bison ${QMAKE_FILE_IN} && $$biso.commands
QMAKE_EXTRA_COMPILERS += biso_header
HEADERS += src/AST.h \
src/ModuleInstantiation.h \
src/Package.h \
@ -242,14 +272,16 @@ HEADERS += src/AST.h \
src/expression.h \
src/function.h \
src/module.h \
src/UserModule.h
src/UserModule.h \
SOURCES += src/AST.cc \
src/ModuleInstantiation.cc \
src/expr.cc \
src/function.cc \
src/module.cc \
src/UserModule.cc
src/UserModule.cc \
src/annotation.cc \
src/assignment.cc
HEADERS += src/version_check.h \
src/ProgressWidget.h \
@ -350,7 +382,9 @@ HEADERS += src/version_check.h \
src/AutoUpdater.h \
src/launchingscreen.h \
src/legacyeditor.h \
src/LibraryInfoDialog.h
src/LibraryInfoDialog.h \
\
src/comment.h\
SOURCES += \
src/libsvg/libsvg.cc \
@ -473,7 +507,9 @@ SOURCES += \
src/FontListTableView.cc \
src/launchingscreen.cc \
src/legacyeditor.cc \
src/LibraryInfoDialog.cc
src/LibraryInfoDialog.cc\
\
src/comment.cpp
# ClipperLib
SOURCES += src/polyclipping/clipper.cpp

View file

@ -1,13 +1,23 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include <utility>
#include "value.h"
#include "AST.h"
#include "memory.h"
class Assignment : public ASTNode
class Annotation;
typedef std::map<std::string, Annotation *> AnnotationMap;
typedef std::vector<Annotation> AnnotationList;
class Assignment : public ASTNode
{
public:
Assignment(std::string name, const Location &loc)
@ -16,9 +26,44 @@ public:
shared_ptr<class Expression> expr = shared_ptr<class Expression>(),
const Location &loc = Location::NONE)
: ASTNode(loc), name(name), expr(expr) { }
std::string name;
shared_ptr<class Expression> expr;
};
typedef std::vector<Assignment> AssignmentList;
virtual void add_annotations(AnnotationList *annotations);
virtual bool has_annotations() const;
virtual const Annotation * annotation(const std::string &name) const;
protected:
AnnotationMap annotations;
};
typedef std::vector<Assignment> AssignmentList;
class Annotation
{
protected:
Annotation(const std::string name, const AssignmentList assignments, const AssignmentList args);
public:
virtual ~Annotation();
std::string dump() const;
const std::string & get_name();
virtual ValuePtr evaluate(class Context *ctx, const std::string& var) const;
Annotation& operator=(const Annotation&);
static const Annotation * create(const std::string name, const AssignmentList assignments);
//private:
std::string name;
/** Defines the names and values parsed from the script */
AssignmentList assignments;
private:
/** Defines the names of the positional parameters */
AssignmentList args;
};

94
src/annotation.cc Normal file
View file

@ -0,0 +1,94 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* 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.
*
* As a special exception, you have permission to link this program
* with the CGAL library and distribute executables, as long as you
* follow the requirements of the GNU GPL in regard to all of the
* software in the executable aside from CGAL.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "Assignment.h"
#include "expression.h"
#include "context.h"
#include "evalcontext.h"
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
Annotation::Annotation(const std::string name, const AssignmentList assignments, const AssignmentList args)
: name(name), assignments(assignments), args(args)
{
}
Annotation::~Annotation()
{
}
const Annotation * Annotation::create(const std::string name, const AssignmentList assignments)
{
AssignmentList args;
if (name == "Description") {
args += Assignment("text");
} else if (name == "Parameter") {
args += Assignment("values");
}
else if (name == "Group") {
args += Assignment("text");
}
return new Annotation(name, assignments, args);
}
Annotation& Annotation::operator=(const Annotation& other)
{
name = other.name;
assignments = other.assignments;
return *this;
}
ValuePtr Annotation::evaluate(class Context *ctx, const std::string& var) const
{
Context c(ctx);
EvalContext ec(&c, assignments);
c.setVariables(args, &ec);
const ValuePtr v = c.lookup_variable(var, true);
return v;
}
const std::string & Annotation::get_name()
{
return name;
}
std::string Annotation::dump() const
{
std::stringstream dump;
dump << "@" << name << "(";
for(const auto &ass : this->assignments) {
dump << *ass.expr <<")"<< std::endl;
}
if(this->assignments.empty()){
dump <<")"<< std::endl;
}
return dump.str();
}

47
src/assignment.cc Normal file
View file

@ -0,0 +1,47 @@
/*
* OpenSCAD (www.openscad.org)
* Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
* Marius Kintel <marius@kintel.net>
*
* 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.
*
* As a special exception, you have permission to link this program
* with the CGAL library and distribute executables, as long as you
* follow the requirements of the GNU GPL in regard to all of the
* software in the executable aside from CGAL.
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "Assignment.h"
void Assignment::add_annotations(AnnotationList *annotations)
{
for (AnnotationList::iterator it = annotations->begin();it != annotations->end();it++) {
this->annotations.insert(std::pair<const std::string, Annotation *>((*it).get_name(), &(*it)));
}
}
bool Assignment::has_annotations() const
{
return !annotations.empty();
}
const Annotation * Assignment::annotation(const std::string &name) const
{
AnnotationMap::const_iterator it = annotations.find(name);
return it == annotations.end() ? NULL : (*it).second;
}

274
src/comment.cpp Normal file
View file

@ -0,0 +1,274 @@
#include "comment.h"
/*
Insert Parameters in AST of given scad file
in form of annotations
*/
void addParameter(const char *fulltext, class FileModule *root_module){
//Getting list of all group names in the file
GroupList groupList = collectGroups(std::string(fulltext));
for (AssignmentList::iterator it = root_module->scope.assignments.begin();it != root_module->scope.assignments.end();it++) {
//get loaction of assignment node
const Location locate=(*it).location();
int loc =locate.firstLine();
// makeing list to add annotations
AnnotationList *annotationList = new AnnotationList();
AssignmentList *assignmentList;
//extracting the parameter
string name = getParameter(std::string(fulltext),loc);
if(name!= "" ){
//getting the node for parameter annnotataion
assignmentList=parser(name.c_str());
if(assignmentList!=NULL){
const Annotation *Parameter;
Parameter=Annotation::create("Parameter",*assignmentList);
// adding parameter to the list
annotationList->push_back(*Parameter);
}
}
//extracting the description
name = getDescription(std::string(fulltext),loc-1);
if(name!= ""){
//creating node for description
assignmentList=new AssignmentList();
Expression *expr;
expr=new Literal(ValuePtr(std::string(name.c_str())));
Assignment *assignment;
assignment=new Assignment("", shared_ptr<Expression>(expr));
assignmentList->push_back(*assignment);
const Annotation * Description;
Description=Annotation::create("Description", *assignmentList);
annotationList->push_back(*Description);
}
// Look for the group to which the given assignment belong
int i=0;
for( ;i<groupList.size() && groupList[i].lineNo<loc;i++){
}
i--;
if(i>=0){
//creating node for description
assignmentList=new AssignmentList();
Expression *expr;
expr=new Literal(ValuePtr(groupList[i].commentString));
Assignment *assignment;
assignment=new Assignment("", shared_ptr<Expression>(expr));
assignmentList->push_back(*assignment);
const Annotation * Description;
Description=Annotation::create("Group", *assignmentList);
annotationList->push_back(*Description);
}
(*it).add_annotations(annotationList);
}
}
/*
gives the string parameter for given
Assignment
*/
string getParameter(string fulltext, int loc){
unsigned int start = 0;
if( loc<1){
return "";
}
for(; start<fulltext.length() ; start++){
if(fulltext[start]=='\n')
loc--;
if(loc<=1)
break;
}
int end=start+1;
while(fulltext[end]!='\n'){
end++;
}
string comment = fulltext.substr(start,end-start);
unsigned int startText=0;
int noOfSemicolon=0;
bool isComment=true;
for(;startText<comment.length()-1;startText++){
if(comment[startText]=='\"' || comment[startText]=='\''){
isComment=!isComment;
}
if( comment[startText]== '/' && comment[startText+1]=='/' && isComment){
break;
}
if(comment[startText]== ';' && isComment && noOfSemicolon>0){
return "";
}
if(comment[startText]== ';' && isComment){
noOfSemicolon++;
}
}
if(startText+2>comment.length()){
return "";
}
return comment.substr(startText+2);
}
/*
Gives the string of Description for given
Assignment
*/
string getDescription(string fulltext, int loc){
unsigned int start = 0;
if( loc<1){
return "";
}
for(; start<fulltext.length() ; start++){
if(loc<=1)
break;
if(fulltext[start]=='\n')
loc--;
}
//not a valid description
if(fulltext[start] != '/' || fulltext[start+1] != '/'){
return "";
}
//Jump over the two forward slashes
start=start+2;
//Jump over all the spaces
while(fulltext[start]==' ' || fulltext[start]=='\t'){
start++;
}
string retString = "";
//go till the end of the line
while(fulltext[start]!='\n'){
//replace // with space
if(fulltext[start] == '/' && fulltext[start+1] == '/'){
retString += " ";
start++;
}else{
retString += fulltext[start];
}
start++;
}
return retString;
}
/*
This function collect the list of groups of Parameter decsibred in
scad file
*/
GroupList collectGroups(string fulltext){
GroupList groupList; //container of all group names
int lineNo=1; // tracks line number
bool isComment=true; //check if its string or comment
//iterate through whole scad file
for(unsigned int i=0; i<fulltext.length(); i++){
//increase line number
if(fulltext[i]=='\n'){
lineNo++;
}
//start or end of string negate the checkpoint
if(fulltext[i]=='\"' || fulltext[i]=='\''){
isComment=!isComment;
}
//start of multi line comment if check is true
if(fulltext[i]=='/' && fulltext[i+1]=='*' && isComment){
//store comment
string comment;
i=i+2;
// till */ every character is comment
while(fulltext[i]!='*' && fulltext[i+1]!='/'){
comment+=fulltext[i];
i++;
}
//store info related to group
GroupInfo groupInfo;
string finalGroupName; //Final group name
string groupName; //group name
bool isGroupName=false;
for(unsigned int it=0; it<comment.length();it++){
//Start of Group Name
if(comment[it]=='[' ){
isGroupName=true;
continue;
}
//End of Group Name
if(comment[it]==']' ){
isGroupName=false;
//Setting of group name
if(!finalGroupName.empty()){
finalGroupName=finalGroupName+"-"+groupName;
}else{
finalGroupName=finalGroupName+groupName;
}
groupName.clear();
continue;
}
//collect characters if it belong to group name
if(isGroupName){
groupName+=comment[it];
}
}
groupInfo.commentString=finalGroupName;
groupInfo.lineNo=lineNo;
groupList.push_back(groupInfo);
}
}
return groupList;
}

26
src/comment.h Normal file
View file

@ -0,0 +1,26 @@
#ifndef COMMENT_H
#define COMMENT_H
#include "expression.h"
#include"Assignment.h"
#include "FileModule.h"
#include <string>
#include<vector>
using namespace std;
extern AssignmentList * parser(const char *text);
struct GroupInfo{
string commentString;
int lineNo;
};
typedef vector <GroupInfo> GroupList;
GroupList collectGroups(string fulltext);
string getParameter(string fulltext, int loc);
string getDescription(string fulltext, int loc);
void addParameter(const char *fulltext, class FileModule *root_module);
#endif // COMMENT_H

46
src/comment_lexer.l Normal file
View file

@ -0,0 +1,46 @@
%{
#include "Assignment.h"
#include "expression.h"
#include "value.h"
#include "comment_parser.h"
#include <boost/lexical_cast.hpp>
YY_BUFFER_STATE yy_scan_string ( const char *str ) ;
%}
%x cond_string
D [0-9]
E [Ee][-+]?{D}+
H [0-9a-fA-F]
%%
[+-]?{D}+{E}? |
[+-]?{D}*\.{D}+{E}? |
[+-]?{D}+\.{D}*{E}? {
try {
yylval.num = boost::lexical_cast<double>(yytext);
return NUM;
} catch (boost::bad_lexical_cast) {}
}
"[" { return yytext[0];}
"]" { return yytext[0];}
"," { return yytext[0];}
":" { return yytext[0];}
[ \t]
[^(\[ \] \, \:)]* { yylval.text=strdup(yytext); return WORD;}
. { }
%%
int yywrap(void) {
return 1;
}

141
src/comment_parser.y Normal file
View file

@ -0,0 +1,141 @@
%{
#include<iostream>
#include<string.h>
using namespace std;
#include "Assignment.h"
#include "expression.h"
#include "printutils.h"
#include "value.h"
void yyerror(char *);
int yylex(void);
AssignmentList *argument;
extern void yy_scan_string ( const char *str );
%}
%union {
char *text;
char ch;
double num;
class Expression *expr;
class Vector *vec;
Assignment *arg;
AssignmentList *args;
};
%token<num> NUM
%token<text> WORD
%type <text> word
%type <expr> expr
%type <args> arguments_call
%type <arg> argument_call
%type <vec> vector_expr
%type <vec> labled_vector
%%
arguments_call:
argument_call
{
$$ = new AssignmentList();
$$->push_back(*$1);
argument=$$;
delete $1;
}
;
argument_call:
expr
{
$$ = new Assignment("", shared_ptr<Expression>($1));
}
;
expr :
NUM
{
$$ = new Literal(ValuePtr($1));
}
| word
{
$$ = new Literal(ValuePtr(std::string($1)));
free($1);
}
| '[' optional_commas ']'
{
$$ = new Literal(ValuePtr(Value::VectorType()));
}
| '[' vector_expr optional_commas ']'
{
$$ = $2;
}
| '[' expr ':' expr ']'
{
$$ = new Range($2, $4,Location::NONE);
}
| '[' expr ':' expr ':' expr ']'
{
$$ = new Range($2, $4, $6,Location::NONE);
}
| labled_vector { $$=$1;}
;
labled_vector:
expr ':' expr {
$$ = new Vector(Location::NONE);
$$->push_back($1);
$$->push_back($3);
}
;
optional_commas:
',' optional_commas
| /* empty */
;
vector_expr:
expr
{
$$ = new Vector(Location::NONE);
$$->push_back($1);
}
| vector_expr ',' optional_commas expr
{
$$ = $1;
$$->push_back($4);
}
;
word:
WORD
{
$$=$1;
}
| word WORD
{
string a;
a=$1;
a+=" ";
a+=$2;
$$=strdup(a.c_str());
}
%%
void yyerror(char *msg) {
PRINTD("ERROR IN PARAMETER: Parser error in comments of file \n ");
cout<<msg<<endl;
argument=NULL;
}
AssignmentList * parser(const char *text) {
yy_scan_string(text);
int parserretval = yyparse();
if (parserretval != 0) return NULL;
return argument;
}

View file

@ -32,7 +32,23 @@ std::string LocalScope::dump(const std::string &indent) const
dump << m.second->dump(indent, m.first);
}
for(const auto &ass : this->assignments) {
dump << indent << ass.name << " = " << *ass.expr << ";\n";
if( ass.has_annotations()){
const Annotation *Description=ass.annotation("Description");
if( Description != NULL){
dump<<Description->dump();
}
const Annotation *parameter =ass.annotation("Parameter");
if( parameter != NULL){
dump<<parameter->dump();
}
dump << indent << ass.name << " = " << *ass.expr << ";\n";
}
else{
dump << indent << ass.name << " = " << *ass.expr << ";\n";
}
}
for(const auto &inst : this->children) {
dump << inst->dump(indent);

View file

@ -24,6 +24,7 @@
*
*/
#include <iostream>
#include "comment.h"
#include "openscad.h"
#include "GeometryCache.h"
#include "ModuleCache.h"
@ -1699,6 +1700,11 @@ void MainWindow::compileTopLevelDocument()
const char* fname =
this->fileName.isEmpty() ? "" : fnameba;
this->root_module = parse(fulltext.c_str(), fs::path(fname), false);
if(this->root_module!=NULL)
//add parameters as annotation in AST
addParameter(fulltext.c_str(),this->root_module);
}
void MainWindow::checkAutoReload()

View file

@ -25,6 +25,7 @@
*/
#include "openscad.h"
#include "comment.h"
#include "node.h"
#include "module.h"
#include "ModuleInstantiation.h"
@ -399,6 +400,10 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
PRINTB("Can't parse file '%s'!\n", filename.c_str());
return 1;
}
// add parameter to AST
addParameter(text.c_str(),root_module);
root_module->handleDependencies();
fs::path fpath = fs::absolute(fs::path(filename));

View file

@ -200,9 +200,10 @@ assignment:
}
}
if (!found) {
scope_stack.top()->assignments.push_back(Assignment($1, shared_ptr<Expression>($3)));
scope_stack.top()->assignments.push_back(Assignment($1, shared_ptr<Expression>($3),LOC(@$)));
}
free($1);
}
;