Valider d7b93475 rédigé par esj's avatar esj
Parcourir les fichiers

Ce perdant de PHP étant incapable de donner la ligne d'une faute de syntaxe...

Ce perdant de PHP étant incapable de donner la ligne d'une faute de syntaxe sans provoquer une erreur fatale, on fait désormais retourner à {{{public_compiler}}} non plus la concaténation des fonctions compilées, mais le tableau des boucles, contenant leur code compilé et leur contexte de compilation (plus le code de a fonction pincipale, vu comme une fausse boucle). Cela permet à {{{public_composer}}}:

	* d'executer {{{if (@eval("return true; $code")) }}} sur le code de chaque fonction isolément, pour ne pas perdre la main en cas d'erreur de syntaxe et dire dans quelle boucle l'erreur se produit;

	* de donner le contexte de compilation de la fonction fautive au débusqueur, qui peut ainsi construire ses liens de navigation, en particulier le lien "code" de la boucle fautive, ce qui permet enfin au débusqueur d'afficher du code PHP fautif, qu'on pourra éventuellement copier dans un fichier pour relecture par l'interpréte PHP pour refaire apparaître, mais hors site, le numéro de ligne.

J'aurais bien aimé dispenser de cette dernière manipulation, mais ça semble définitivement impossible en PHP. Au moins, on n'a plus à trafiquer composer.php et/ou lire le cache des squelettes compilés pour localiser l'erreur, surtout quand on n'a pas les [http://videos.spip.org/spip.php?article115 outils de Cédric].

La spécification du résultat de la fonction {{{public_compiler}}} est donc changée, mais ça ne concerne que ceux qui manipulent le code compilé explicitement.
parent 43f542b1
Chargement en cours
Chargement en cours
Chargement en cours
Chargement en cours
+34 −50
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -796,19 +796,20 @@ function compile_inclure_doublons($lexemes)
	return false;
}

// Prend en argument le texte d'un squelette (et son fichier d'origine)
// sa grammaire et un nom.
// Retourne une fonction PHP/SQL portant ce nom et calculant une page.
// Prend en argument le texte d'un squelette, le nom de son fichier d'origine,
// sa grammaire et un nom. Retourne False en cas d'erreur,
// sinon retourne un tableau de fonctions PHP compilees a evaluer,
// notamment une fonction portant ce nom et calculant une page.
// Pour appeler la fonction produite, lui fournir 2 tableaux de 1 e'le'ment:
// - 1er: element 'cache' => nom (du fichier ou` mettre la page)
// - 2e: element 0 contenant un environnement ('id_article => $id_article, etc)
// Elle retourne alors un tableau de 5 e'le'ments:
// Elle retournera alors un tableau de 5 e'le'ments:
// - 'texte' => page HTML, application du squelette a` l'environnement;
// - 'squelette' => le nom du squelette
// - 'process_ins' => 'html' ou 'php' selon la pre'sence de PHP dynamique
// - 'invalideurs' =>  de'pendances de cette page, pour invalider son cache.
// - 'entetes' => tableau des entetes http
// En cas d'erreur, elle retourne un tableau des 2 premiers elements seulement
// En cas d'erreur, elle retournera un tableau des 2 premiers elements seulement

// http://doc.spip.org/@public_compiler_dist
function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect=''){
@@ -832,7 +833,8 @@ function public_compiler_dist($squelette, $nom, $gram, $sourcefile, $connect='')
	return compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect);
}

// Point d'entree pour arbre de syntaxe abstraite fourni
// Point d'entree pour arbre de syntaxe abstraite fourni en premier argument
// Autres specifications comme ci-dessus

function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $connect=''){
	global $tables_jointures;
@@ -930,7 +932,7 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
		if ($type AND $type != 'boucle') {
			if ($boucle->param) {
				$res = calculer_criteres($id, $boucles);
				if (is_array($res)) return $res; # erreur
				if (is_array($res)) return false; # erreur
			}
			$descr['id_mere'] = $id;
			$boucles[$id]->return =
@@ -981,19 +983,14 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
			$GLOBALS['debug_objets']['code'][$nom.$id] = $boucles[$id]->return;
	}

	if ($debug)
		$code = "\n\n/*\n" . 
			str_replace('*/', '* /', public_decompiler($squelette)) 
			. "\n*/\n";
	else $code = "";

	foreach($boucles as $id => $boucle) {
		$code .= "\n\n/* BOUCLE " .
		$boucle->return = "\n\n/* BOUCLE " .
			$boucle->type_requete .
			" " .
			(!$debug ? '' : 
			str_replace('*/', '* /', 
			       decompiler_criteres($boucle->param, $boucle->criteres))) .
				decompiler_criteres($boucle->param, 
						$boucle->criteres))) .
			" */\n\n " .
			$boucle->return;
	}
@@ -1001,31 +998,20 @@ function compiler_squelette($squelette, $boucles, $nom, $descr, $sourcefile, $co
	$secondes = spip_timer('calcul_skel');
	spip_log("COMPIL ($secondes) [$sourcefile] $nom.php");

	$head = '';
	if (is_array($tableau_des_erreurs))  {
		foreach ($tableau_des_erreurs as $err) {
			$head .= "\n// "
			. str_replace("\n", ' ', $err[0]);
		}
	}

	if (!CODE_COMMENTE)
		$head .= '';
	else $head = "
/*
 * Squelette : $sourcefile
 * Date :      ".gmdate("D, d M Y H:i:s", @filemtime($sourcefile))." GMT
 * Compile :   ".gmdate("D, d M Y H:i:s", time())." GMT ($secondes)
 * " . (!$boucles ?  "Pas de boucle" :
	("Boucles :   " . join (', ', array_keys($boucles)))) ."
 */ " ;

	$code = '<'.'?php' . $head .  $code . '

//
// Fonction principale du squelette ' . $sourcefile . 
	  ($connect ? " pour $connect" : '') . ".
	// Assimiler la fct principale a une boucle anonyme, c'est plus simple
	$code = new Boucle;
	$code->descr = $descr;
	$code->return = '
//
// Fonction principale du squelette ' . 
	$sourcefile . 
	($connect ? " pour $connect" : '') . 
	(!CODE_COMMENTE ? '' : "\n// Temps de compilation total: $secondes") .
	"\n//" .
	(!$debug ? '' : ("\n/*\n" . 
			str_replace('*/', '* /', public_decompiler($squelette)) 
				      . "\n*/")) . "

function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0) {

'
@@ -1044,12 +1030,10 @@ function " . $nom . '($Cache, $Pile, $doublons=array(), $Numrows=array(), $SP=0)

	return analyse_resultat_skel(".var_export($nom,true)
		.", \$Cache, \$page, ".var_export($sourcefile,true).");
}

?".">";

	return $code;
}";

	$boucles[''] = $code;
	return $boucles;
}

?>
+64 −16
Numéro de ligne d'origine Numéro de ligne de diff Ligne de diff
@@ -61,26 +61,74 @@ function public_composer_dist($squelette, $mime_type, $gram, $source, $connect='
		$skel_code = $compiler($skel, $nom, $gram, $source, $connect);
	}

	// Ne plus rien faire si le compilateur renvoie une erreur
	if (!is_array($skel_code)) {
	// Ne plus rien faire si le compilateur n'a pas pu operer.
	if (!$skel_code) return false;

	foreach($skel_code as $id => $boucle) {
		$f = $boucle->return;
		if (@eval("return true; $f ;") ===  false) {
		// Code syntaxiquement faux (critere etc mal programme')
			erreur_squelette(_T('zbug_erreur_compilation'), $boucle); 
			// continuer pour trouver d'autres fautes eventuelles
			// mais prevenir que c'est mort
			$nom = '';
		} 
		// Contexte de compil inutile a present
		// (mais la derniere valeur de $boucle est utilisee ci-dessous)
		$skel_code[$id] = $f;
	}

	if ($nom) {
		// Si le code est bon, concatener et mettre en cache
		if (function_exists($nom))
			$code = squelette_traduit($skel, $source, $phpfile, $skel_code);
		else {
			// code semantiquement faux: bug du compilateur
			erreur_squelette(_T('zbug_erreur_compilation'), $boucle);
			$nom = '';
		}
	}

		// si c'est ce que demande le debusqueur, lui passer la main
	if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode'] == 'debug') {

		// Tracer ce qui vient d'etre compile
		$GLOBALS['debug_objets']['code'][$nom . 'tout'] = $skel_code;

		// si c'est ce que demande le debusqueur, lui passer la main
		if ($GLOBALS['debug_objets']['sourcefile']
		AND (_request('var_mode_objet') == $nom)
			AND (_request('var_mode_affiche') == 'code')
)
				erreur_squelette('', $skel_code);
		AND (_request('var_mode_affiche') == 'code')  )
			erreur_squelette('', $code);
	}
		eval('?'.'>'.$skel_code);
		if (function_exists($nom)) {
			ecrire_fichier ($phpfile, $skel_code);
			return array($nom, $skel_code);
		} else {
			erreur_squelette(_T('zbug_erreur_compilation'), $source);
	return $nom ? array($nom, $code) : false;
}

function squelette_traduit($squelette, $sourcefile, $phpfile, $boucles)
{
	global $tableau_des_erreurs;

	$code = '';
	if (is_array($tableau_des_erreurs))  {
		foreach ($tableau_des_erreurs as $err) {
			$code .= "\n// "
			. str_replace("\n", ' ', $err[0]);
		}
	}

	// Le dernier index est '' (fonction principale)
	$noms = substr(join (', ', array_keys($boucles)), 0, -2);
	if (CODE_COMMENTE)
	$code = "
/*
 * Squelette : $sourcefile
 * Date :      ".gmdate("D, d M Y H:i:s", @filemtime($sourcefile))." GMT
 * Compile :   ".gmdate("D, d M Y H:i:s", time())." GMT
 * " . (!$boucles ?  "Pas de boucle" :	("Boucles :   " . $noms)) ."
 */ " ;

	$code = '<'. "?php\n" . $code . join('', $boucles)  . "\n" .'>';
	ecrire_fichier($phpfile, $code);
	return $code;
}

// Le squelette compile est-il trop vieux ?