File:  [parser3project] / parser3 / src / types / pa_value.h
Revision 1.178: download - view: text, annotated - select for diffs - revision graph
Sat Apr 25 13:38:46 2026 UTC (7 weeks, 2 days ago) by moko
Branches: MAIN
CVS tags: HEAD
Copyright year updated, websites links changed to https://

/** @file
	Parser: Value, Method, Junction .

	Copyright (c) 2001-2026 Art. Lebedev Studio (https://www.artlebedev.com)
	Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
*/

#ifndef PA_VALUE_H
#define PA_VALUE_H

#define IDENT_PA_VALUE_H "$Id: pa_value.h,v 1.178 2026/04/25 13:38:46 moko Exp $"

#include "pa_common.h"
#include "pa_array.h"
#include "pa_exception.h"
#include "pa_property.h"
#include "pa_opcode.h"

// forwards

class VStateless_class;
class WContext;
class Request;
class Request_charsets;
class Junction;
class VJunction;
class Method;
class Value;
class MethodParams;
class VObject;
class VMethodFrame;
class VFile;
class Table;
struct XDocOutputOptions;

template <typename T>class SparseArray;
typedef SparseArray<Value*> ArrayValue;

struct Json_options : public PA_Allocated {
	Request* r;
	String::Body key;
	HashStringValue* methods;
	Value* default_method;
	Value* params;
	bool skip_unknown;
	bool one_line;
	uint json_string_recursion;
	const char* indent;
	XDocOutputOptions* xdoc_options;
	enum Date { D_SQL, D_GMT, D_ISO, D_TIMESTAMP } date;
	enum Table { T_ARRAY, T_OBJECT, T_COMPACT } table;
	enum Array { A_ARRAY, A_OBJECT, A_COMPACT } array;
	enum File { F_BODYLESS, F_BASE64, F_TEXT } file;
	enum Void { V_NULL, V_STRING } fvoid;

	Json_options(Request* arequest):
		r(arequest),
		methods(NULL),
		default_method(NULL),
		params(NULL),
		skip_unknown(false),
		one_line(false),
		json_string_recursion(0),
		indent(NULL),
		xdoc_options(NULL),
		date(D_SQL),
		table(T_OBJECT),
		array(A_COMPACT),
		file(F_BODYLESS),
		fvoid(V_NULL)
	{}

	bool set_date_format(const String &value){
		if(value == "sql-string") date = D_SQL;
		else if (value == "gmt-string") date = D_GMT;
		else if (value == "iso-string") date = D_ISO;
		else if (value == "unix-timestamp") date = D_TIMESTAMP;
		else return false;
		return true;
	}

	bool set_table_format(const String &value){
		if(value == "array") table = T_ARRAY;
		else if (value == "object") table = T_OBJECT;
		else if (value == "compact") table = T_COMPACT;
		else return false;
		return true;
	}

	bool set_array_format(const String &value){
		if(value == "array") array = A_ARRAY;
		else if (value == "object") array = A_OBJECT;
		else if (value == "compact") array = A_COMPACT;
		else return false;
		return true;
	}

	bool set_file_format(const String &value){
		if(value == "base64") file = F_BASE64;
		else if (value == "text") file = F_TEXT;
		else if (value == "stat") file = F_BODYLESS;
		else return false;
		return true;
	}

	bool set_void_format(const String &value){
		if(value == "null") fvoid = V_NULL;
		else if(value == "string") fvoid = V_STRING;
		else return false;
		return true;
	}

	const String* hash_json_string(HashStringValue *hash);
	const String* array_json_string(ArrayValue *array);
	const String* array_compact_json_string(ArrayValue *array);
};

///	grandfather of all @a values in @b Parser
class Value: public PA_Object {
public: // Value

	/// value type, used for error reporting and 'is' expression operator
	virtual const char* type() const =0;

	/**
		all except VObject/VClass: true if @atype eq type()
		VObject/VClass: can locate parent class by it's type
	*/
	virtual bool is(const char* atype) { return atype && strcmp(type(), atype)==0; }

	/// is this value defined?
	virtual bool is_defined() const { return true; }

	/// is this value string?
	virtual bool is_string() const { return false; }

	/// is this value void?
	virtual bool is_void() const { return false; }

	/// is this value bool?
	virtual bool is_bool() const { return false; }

	/// is this value number?
	virtual bool is_evaluated_expr() const { return false; }

	/// what's the meaning of this value in context of expression?
	virtual Value& as_expr_result() {
		return *bark("is '%s', cannot be used in expression"); 
	}

	/** extract HashStringValue if any
		WARNING: FOR LOCAL USE ONLY, THIS POINTER IS NOT TO PASS TO ANYBODY!
	*/
	virtual HashStringValue* get_hash() { return 0; }

	/// extract const String
	virtual const String* get_string() { return 0; }

	/// extract json-string
	virtual const String* get_json_string(Json_options& options);
	const String* default_method_2_json_string(Value& default_method, Json_options& options);

	/// for reflection
	virtual HashStringValue* get_fields() { return 0; }
	virtual HashStringValue* get_fields_reference() { return 0; }

	/// extract double
	virtual double as_double() const { bark("is '%s', it does not have numerical (double) value"); return 0; }

	/// extract integer
	virtual int as_int () const { bark("is '%s', it does not have numerical (int) value"); return 0; }

	/// extract wide integer
	virtual pa_wint as_wint () const { return as_int(); }

	/// extract bool
	virtual bool as_bool() const { bark("is '%s', it does not have logical value"); return 0; }

	/// extract file
	virtual VFile* as_vfile();
	virtual VFile* as_vfile(String::Language /*lang*/, const Request_charsets* /*charsets*/) { return as_vfile(); }

	/// extract Junction
	virtual Junction* get_junction();

	/// @return Value element; can return Junction for methods; Code-Junction for code; Getter-Junction for property
	virtual Value* get_element(const String& /*aname*/);

#ifdef FEATURE_GET_ELEMENT4CALL
	/// same as get_element, but methods have higher priority in table and hash
	virtual Value* get_element4call(const String& aname){
		return get_element(aname);
	}
#endif

	/// store Value element under @a name
	/// @returns putter method junction, or 0
	virtual const VJunction* put_element(const String& aname, Value* /*avalue*/) { 
		// to prevent modification of system classes,
		// created at system startup, and not having exception
		// handler installed, we neet to bark using request.pool
		bark("element cannot be stored into %s", &aname); 
		return 0;
	}

	/// VObject default getter & setter support
	virtual void enable_default_getter(){ }
	virtual void enable_default_setter(){ }
	virtual void disable_default_getter(){ }
	virtual void disable_default_setter(){ }
	virtual bool is_enabled_default_getter(){ return true; }
	virtual bool is_enabled_default_setter(){ return true; }

	/// extract VStateless_class
	virtual VStateless_class* get_class()=0;

	/// extract base class, if any
	virtual VStateless_class* base() { return 0; }

	/// extract VTable
	virtual Table* get_table() { return 0; }

	/// warning war, no overhead as destructors are called manually only when required
	virtual ~Value() {}

public: // usage

	/// @return sure String or barks if it doesn't have string value
	const String& as_string() {
		const String* result=get_string();
		if(!result)
			bark("is '%s', it has no string representation");

		return *result;
	}

	/// @return Hash or barks if it is not hash compatible
	HashStringValue* as_hash(const char* name=0);

	/// throws exception specifying bark-reason and name() type() of problematic value
	Value* bark(const char *reason, const String *problem_source=0) const {
		throw Exception(PARSER_RUNTIME, problem_source, reason, type());
	}

};

/**
	$content-type[text/html] ->
		content-type: text/html
	$content-type[$.value[text/html] $.charset[windows-1251]] ->
		content-type: text/html; charset=windows-1251
*/
const String& attributed_meaning_to_string(Value& meaning, String::Language lang, bool forced=false, bool allow_bool=false);

// defines

///@{common field names
#define CHARSET_NAME "charset"
#define VALUE_NAME "value"
#define EXPIRES_NAME "expires"
#define CONTENT_TYPE_NAME "content-type"
#define NAME_NAME "name"
//@}

///@{common field names
extern const String value_name;
extern const String expires_name;
extern const String content_type_name;
extern const String name_name;
///@}

#endif

E-mail: